sql >> データベース >  >> RDS >> Sqlserver

例を使用したOPENJSONの概要(SQL Server)

    SQL Serverには、OPENJSON()と呼ばれるテーブル値関数があります。 JSONデータのリレーショナルビューを作成します。

    これを呼び出すときは、JSONドキュメントを引数として渡し、OPENJSON() 次に、それを解析し、JSONドキュメントのオブジェクトとプロパティを表形式で行と列として返します。

    簡単な例を次に示します。

    SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');

    結果:

    +-------+---------+--------+
    | key   | value   | type   |
    |-------+---------+--------|
    | 0     | Cat     | 1      |
    | 1     | Dog     | 1      |
    | 2     | Bird    | 1      |
    +-------+---------+--------+

    デフォルトでは、OPENJSON() 3列のテーブルを返します。 キー 、およびタイプ

    独自のスキーマを指定するオプションもあります(つまり、独自の列を定義できます)。簡単な例では、デフォルトスキーマを使用したため、3つのデフォルト列が返されました。

    これらの列は次のように定義されています。

    説明
    キー 指定されたプロパティの名前または指定された配列内の要素のインデックスが含まれます。これはnvarchar(4000)です 値であり、列にはBIN2照合があります。
    プロパティの値が含まれます。これはnvarchar(max)です 値であり、列は提供されたJSONからその照合を継承します。
    タイプ 値のJSONタイプが含まれています。これはintとして表されます 値(0から 5へ )。この列は、デフォルトのスキーマを使用する場合にのみ返されます。

    デフォルトタイプ

    JSONの世界には、6つのデータ型があります。これらは文字列です 、番号 true / false (ブール値)、 null オブジェクト 、および配列

    OPENJSON()を介してJSONを解析する場合 デフォルトのスキーマであるOPENJSON()を使用します JSONタイプが何であるかを理解し、タイプにデータを入力します intの列 そのタイプを表す値。

    int したがって、値の範囲は0になります。 5へ 。各int 値は、次の表に概説されているJSONタイプを表します。

    「type」列の値 JSONデータ型
    0 null
    1 文字列
    2 番号
    3 true / false
    4 配列
    5 オブジェクト

    次の例では、これら6つのJSONタイプすべてが返されます。

    SELECT * FROM OPENJSON('{"name" : null}');
    SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');
    SELECT * FROM OPENJSON('[1,2,3]');
    SELECT * FROM OPENJSON('[true,false]');
    SELECT * FROM OPENJSON('{"cats":[{ "id":1, "name":"Fluffy"},{ "id":2, "name":"Scratch"}]}');
    SELECT * FROM OPENJSON('[{"A":1,"B":0,"C":1}]');

    結果:

    +-------+---------+--------+
    | key   | value   | type   |
    |-------+---------+--------|
    | name  | NULL    | 0      |
    +-------+---------+--------+
    (1 row affected)
    +-------+---------+--------+
    | key   | value   | type   |
    |-------+---------+--------|
    | 0     | Cat     | 1      |
    | 1     | Dog     | 1      |
    | 2     | Bird    | 1      |
    +-------+---------+--------+
    (3 rows affected)
    +-------+---------+--------+
    | key   | value   | type   |
    |-------+---------+--------|
    | 0     | 1       | 2      |
    | 1     | 2       | 2      |
    | 2     | 3       | 2      |
    +-------+---------+--------+
    (3 rows affected)
    +-------+---------+--------+
    | key   | value   | type   |
    |-------+---------+--------|
    | 0     | true    | 3      |
    | 1     | false   | 3      |
    +-------+---------+--------+
    (2 rows affected)
    +-------+----------------------------------------------------------+--------+
    | key   | value                                                    | type   |
    |-------+----------------------------------------------------------+--------|
    | cats  | [{ "id":1, "name":"Fluffy"},{ "id":2, "name":"Scratch"}] | 4      |
    +-------+----------------------------------------------------------+--------+
    (1 row affected)
    +-------+---------------------+--------+
    | key   | value               | type   |
    |-------+---------------------+--------|
    | 0     | {"A":1,"B":0,"C":1} | 5      |
    +-------+---------------------+--------+
    (1 row affected)
    >

    ネストされたJSONを返す

    オプションの2番目の引数としてパスを指定することにより、ネストされたオブジェクトまたは配列を返すことができます。

    つまり、JSONドキュメント全体を解析する必要はありません。関心のある部分だけを解析することを選択できます。

    これが例です。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    SELECT * FROM OPENJSON(@json, '$.pets.cats');

    結果:

    +-------+------------------------------------------------------+--------+
    | key   | value                                                | type   |
    |-------+------------------------------------------------------+--------|
    | 0     | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    | 5      |
    | 1     | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } | 5      |
    | 2     | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     | 5      |
    +-------+------------------------------------------------------+--------+

    この場合、$.pets.catsのパスを指定しました 、結果としての価値のみが得られました 返されます。 の価値 は配列であるため、配列全体が返されました。

    1つの猫(つまり、1つの配列要素)だけを返すために、角括弧構文を使用して配列値を返すことができます(この$.pets.cats[1]のように) )。

    これは、1つの配列要素のみを返すように変更された同じ例です。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    SELECT * FROM OPENJSON(@json, '$.pets.cats[1]');

    結果:

    +-------+-----------+--------+
    | key   | value     | type   |
    |-------+-----------+--------|
    | id    | 2         | 2      |
    | name  | Long Tail | 1      |
    | sex   | Female    | 1      |
    +-------+-----------+--------+

    JSON配列インデックスはゼロベースであるため、この例では2番目の配列値が返されました($.pets.cats[1]を指定したため) )。

    $.pets.cats[0]を指定した場合 、最初の値が返されます(つまり、「Fluffy」という名前の猫)。

    スキーマを定義する

    前述のように、独自のスキーマを指定できます(つまり、独自の列とタイプを定義します)。

    これを行う例を次に示します。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    
    SELECT * FROM OPENJSON(@json, '$.pets.cats')
    WITH  (
            [Cat Id]    int             '$.id',  
            [Cat Name]  varchar(60)     '$.name', 
            [Sex]       varchar(6)      '$.sex', 
            [Cats]      nvarchar(max)   '$' AS JSON   
        );

    結果:

    +----------+------------+--------+------------------------------------------------------+
    | Cat Id   | Cat Name   | Sex    | Cats                                                 |
    |----------+------------+--------+------------------------------------------------------|
    | 1        | Fluffy     | Female | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
    | 2        | Long Tail  | Female | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
    | 3        | Scratch    | Male   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
    +----------+------------+--------+------------------------------------------------------+

    列名は、WITHで指定したものを反映していることがわかります。 句。その句では、各JSONキーを自分の好みの列名にマッピングしました。また、各列に必要なSQLServerデータ型を指定しました。

    AS JSONも使用しました 最後の列で、その列をJSONフラグメントとして返します。 AS JSONを使用する場合、データ型は nvarchar(max)である必要があります 。

    データ型を確認する

    次のクエリを使用して、各列のデータ型を確認できます。

    このクエリはsys.dm_exec_describe_first_result_setを使用します クエリからの最初の結果セットに関するメタデータを返すシステム動的管理ビュー。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    
    SELECT 
        name,
        system_type_name
    FROM sys.dm_exec_describe_first_result_set(
        'SELECT * FROM OPENJSON(@json, ''$.pets.cats'') WITH  (
            [Cat Id]    int             ''$.id'',  
            [Cat Name]  varchar(60)     ''$.name'', 
            [Sex]       varchar(6)      ''$.sex'', 
            [Cats]      nvarchar(max)   ''$'' AS JSON 
        )',
        null,
        0
    );

    結果:

    +----------+--------------------+
    | name     | system_type_name   |
    |----------+--------------------|
    | Cat Id   | int                |
    | Cat Name | varchar(60)        |
    | Sex      | varchar(6)         |
    | Cats     | nvarchar(max)      |
    +----------+--------------------+

    それらが私のスキーマと完全に一致していることがわかります。

    キーに注意してください 、 、およびタイプ 独自のスキーマを定義する場合、列は使用できません。これらの列は、デフォルトのスキーマを使用している場合にのみ使用できます。

    解析されたJSONをテーブルに挿入します

    ここまでで、解析されたJSONをデータベーステーブルに簡単に挿入できるとお考えかもしれません。

    そして、あなたは正しいでしょう。

    すでに列と行を用意しており、列に名前を付けてデータ型を指定しています。

    次に、それをテーブルに挿入します。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    
    SELECT * INTO JsonCats
    FROM OPENJSON(@json, '$.pets.cats')
    WITH  (
            [Cat Id]    int             '$.id',  
            [Cat Name]  varchar(60)     '$.name', 
            [Sex]       varchar(6)      '$.sex', 
            [Cats]      nvarchar(max)   '$' AS JSON   
        );

    INTO JsonCatsを追加するだけでした JsonCatsというテーブルを作成するために、私のクエリに クエリの結果を挿入します。

    次に、そのテーブルの内容を選択しましょう。

    SELECT * FROM JsonCats;

    結果:

    +----------+------------+--------+------------------------------------------------------+
    | Cat Id   | Cat Name   | Sex    | Cats                                                 |
    |----------+------------+--------+------------------------------------------------------|
    | 1        | Fluffy     | Female | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
    | 2        | Long Tail  | Female | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
    | 3        | Scratch    | Male   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
    +----------+------------+--------+------------------------------------------------------+

    内容は前の例で見たものとまったく同じです。

    念のため、sys.columnを使用できるようになりました。 システムカタログビューで、テーブルの列名とタイプを確認します。

    SELECT
        name AS [Column],
        TYPE_NAME(system_type_id) AS [Type],
        max_length
    FROM sys.columns 
    WHERE OBJECT_ID('JsonCats') = object_id;

    結果:

    +----------+----------+--------------+
    | Column   | Type     | max_length   |
    |----------+----------+--------------|
    | Cat Id   | int      | 4            |
    | Cat Name | varchar  | 60           |
    | Sex      | varchar  | 6            |
    | Cats     | nvarchar | -1           |
    +----------+----------+--------------+

    繰り返しになりますが、正確に指定した方法です。

    sys.columnsに注意してください 常にmax_lengthを返します -1の 列のデータ型がvarchar(max)の場合 、 nvarchar(max) varbinary(max) 、または xml nvarchar(max)を指定しました したがって、-1の値 期待どおりです。

    パスモード:緩いvs厳密

    2番目の引数またはWITHで指定されたパス 句は(オプションで)laxで始めることができます またはstrict キーワード。

    • laxで モード、OPENJSON() 指定されたパス上のオブジェクトまたは値が見つからない場合でも、エラーは発生しません。パスが見つからない場合は、OPENJSON() 空の結果セットまたはNULLのいずれかを返します 値。
    • strictで モード、OPENJSON() パスが見つからない場合はエラーを返します。

    デフォルト値はlaxです 、したがって、パスモードを指定しない場合は、lax モードが使用されます。

    パスが見つからない場合に各モードで何が起こるかを示すいくつかの例を次に示します。

    2番目の引数

    次の2つの例では、OPENJSON()を呼び出すときに、2番目の引数に存在しないパスを指定します。 。最初の例は、緩いモードを使用したときに何が起こるかを示し、2番目の例は、厳密なモードを使用したときに何が起こるかを示しています。

    ラックスモード

    laxで何が起こるかを次に示します。 パスが見つからない場合はモード。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    SELECT * FROM OPENJSON(@json, 'lax $.pets.cows');

    結果:

    (0 rows affected)

    エラーはありません。返された結果はゼロです。

    厳密モード

    これで、strictになりました モード。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }'
    SELECT * FROM OPENJSON(@json, 'strict $.pets.cows');

    結果:

    Msg 13608, Level 16, State 3, Line 15
    Property cannot be found on the specified JSON path.

    予想どおり、厳密モードではエラーが発生しました。

    WITH句内

    次の2つの例では、緩いモードと厳密なモードを再度テストします。ただし、今回はWITHで指定します。 スキーマを定義するときの句。

    ラックスモード

    laxで何が起こるかを次に示します。 モード。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    
    SELECT *
    FROM OPENJSON(@json, '$.pets.cats')
    WITH  (
            [Cat Id]    int             '$.id',  
            [Cat Name]  varchar(60)     '$.name', 
            [Born]      date            'lax $.born', 
            [Cats]      nvarchar(max)   '$' AS JSON   
        );

    結果:

    +----------+------------+--------+------------------------------------------------------+
    | Cat Id   | Cat Name   | Born   | Cats                                                 |
    |----------+------------+--------+------------------------------------------------------|
    | 1        | Fluffy     | NULL   | { "id" : 1, "name" : "Fluffy", "sex" : "Female" }    |
    | 2        | Long Tail  | NULL   | { "id" : 2, "name" : "Long Tail", "sex" : "Female" } |
    | 3        | Scratch    | NULL   | { "id" : 3, "name" : "Scratch", "sex" : "Male" }     |
    +----------+------------+--------+------------------------------------------------------+

    この場合、私は'lax $.born'を使用します bornというキーを参照しようとしているためです 、ただし、そのようなキーはJSONには存在しません。

    今回は、見つからない列はNULLになります 値。

    厳密モード

    これで、strictになりました モード。

    DECLARE @json NVARCHAR(4000) = N'{ 
        "pets" : {
                "cats" : [
                { "id" : 1, "name" : "Fluffy", "sex" : "Female" },
                { "id" : 2, "name" : "Long Tail", "sex" : "Female" },
                { "id" : 3, "name" : "Scratch", "sex" : "Male" }
            ],
                "dogs" : [
                { "name" : "Fetch", "sex" : "Male" },
                { "name" : "Fluffy", "sex" : "Male" },
                { "name" : "Wag", "sex" : "Female" }
            ]
        }
    }';
    
    SELECT *
    FROM OPENJSON(@json, '$.pets.cats')
    WITH  (
            [Cat Id]    int             '$.id',  
            [Cat Name]  varchar(60)     '$.name', 
            [Born]      date            'strict $.born', 
            [Cats]      nvarchar(max)   '$' AS JSON   
        );

    結果:

    Msg 13608, Level 16, State 6, Line 16
    Property cannot be found on the specified JSON path.

    今回は'strict $.born'を使用しました 。

    予想どおり、厳密モードではエラーが発生しました。

    互換性レベル

    OPENJSON() 機能は互換性レベル130以上でのみ使用できます。

    データベースの互換性レベルが130未満の場合、SQLServerはOPENJSON()を見つけて実行できません。 、エラーが発生します。

    sys.databasesを使用して、データベースの互換性レベルを確認できます。 カタログビュー。

    互換性レベルは次のように変更できます:

    ALTER DATABASE DatabaseName 
    SET COMPATIBILITY_LEVEL = 150;

    JSONは初めてですか?

    JSONにあまり詳しくない場合は、Quackitで私のJSONチュートリアルを確認してください。


    1. PL/pgSQL内でのINSERT後にデフォルトのシリアル値を取得する

    2. 静的関数と潜水艦

    3. Dapperで挿入を実行して挿入されたIDを返すにはどうすればよいですか?

    4. OPENJSONを使用してSQLServerでネストされたJSONを選択する方法