Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Wprowadzenie do OPENJSON z przykładami (SQL Server)

SQL Server ma funkcję zwracającą tabelę o nazwie OPENJSON() który tworzy relacyjny widok danych JSON.

Kiedy to wywołujesz, przekazujesz dokument JSON jako argument, a OPENJSON() następnie analizuje go i zwraca obiekty i właściwości dokumentu JSON w formacie tabelarycznym – jako wiersze i kolumny.

Przykład

Oto prosty przykład do zademonstrowania.

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

Wynik:

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

Domyślnie OPENJSON() zwraca tabelę z trzema kolumnami; klucz , wartość i wpisz .

Masz również możliwość określenia własnego schematu (co oznacza, że ​​możesz zdefiniować własne kolumny). W moim prostym przykładzie użyłem domyślnego schematu, więc trzy domyślne kolumny zostały zwrócone.

Te kolumny są zdefiniowane w następujący sposób:

Kolumna Opis
klucz Zawiera nazwę określonej właściwości lub indeks elementu w określonej tablicy. To jest nvarchar(4000) wartość, a kolumna ma sortowanie BIN2.
wartość Zawiera wartość właściwości. To jest nvarchar(max) wartość, a kolumna dziedziczy swoje sortowanie z dostarczonego JSON.
typ Zawiera typ JSON wartości. Jest to reprezentowane jako int wartość (od 0 do 5 ). Ta kolumna jest zwracana tylko wtedy, gdy używasz domyślnego schematu.

Typy domyślne

W świecie JSON istnieje sześć typów danych. To są ciągi , liczba , prawda/fałsz (wartość logiczna), null , obiekt i tablica .

Kiedy parsujesz JSON za pomocą OPENJSON() używając domyślnego schematu, OPENJSON() sprawdza, jaki jest typ JSON, a następnie wypełnia typ kolumna z int wartość reprezentująca ten typ.

int wartość może zatem wynosić od 0 do 5 . Każdy int wartość reprezentuje typ JSON, jak przedstawiono w poniższej tabeli.

Wartość w kolumnie „typ” Typ danych JSON
0 null
1 ciąg
2 liczba
3 prawda/fałsz
4 tablica
5 obiekt

Poniższy przykład zwraca wszystkie sześć z tych typów 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}]');

Wynik:

+-------+---------+--------+
| 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)

Zwróć zagnieżdżony plik JSON

Możesz zwrócić zagnieżdżony obiekt lub tablicę, określając jego ścieżkę jako opcjonalny drugi argument.

Innymi słowy, nie musisz analizować całego dokumentu JSON – możesz przeanalizować tylko tę część, która Cię interesuje.

Oto przykład.

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');

Wynik:

+-------+------------------------------------------------------+--------+
| 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      |
+-------+------------------------------------------------------+--------+

W tym przypadku określiłem ścieżkę $.pets.cats , co zaowocowało tylko wartością kotów zostanie zwrócony. Wartość kotów jest tablicą, więc cała tablica została zwrócona.

Aby zwrócić tylko jeden cat (tj. jeden element tablicy), możemy użyć składni nawiasów kwadratowych do zwracania wartości tablicy (tak jak ta $.pets.cats[1] ).

Oto ten sam przykład zmodyfikowany tak, aby zwracał tylko jeden element tablicy:

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]');

Wynik:

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

Indeksy tablicy JSON są liczone od zera, więc ten przykład zwrócił drugą wartość tablicy (ponieważ określiłem $.pets.cats[1] ).

Gdybym określił $.pets.cats[0] , zostanie zwrócona pierwsza wartość (tj. kot o imieniu „Puszysty”).

Zdefiniuj schemat

Jak wspomniano, możesz określić własny schemat (tj. Zdefiniuj własne kolumny i typy).

Oto przykład tego.

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   
    );

Wynik:

+----------+------------+--------+------------------------------------------------------+
| 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" }     |
+----------+------------+--------+------------------------------------------------------+

Widzimy, że nazwy kolumn odzwierciedlają te, które określiłem w WITH klauzula. W tej klauzuli zmapowałem każdy klucz JSON do moich własnych preferowanych nazw kolumn. Określiłem również typ danych SQL Server, który chcę dla każdej kolumny.

Użyłem również AS JSON w ostatniej kolumnie, aby zwrócić tę kolumnę jako fragment JSON. Gdy używasz AS JSON, typem danych musi być nvarchar(max) .

Zweryfikuj typy danych

Możemy użyć następującego zapytania, aby zweryfikować typy danych w każdej kolumnie.

To zapytanie używa sys.dm_exec_describe_first_result_set dynamiczny widok zarządzania systemem, który zwraca metadane dotyczące pierwszego zestawu wyników zapytania.

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
);

Wynik:

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

Widzimy, że idealnie pasują do mojego schematu.

Zwróć uwagę, że klawisz , wartość i wpisz kolumny nie są dostępne podczas definiowania własnego schematu. Te kolumny są dostępne tylko w przypadku korzystania z domyślnego schematu.

Wstaw przeanalizowany plik JSON do tabeli

Do tej pory możesz pomyśleć, że moglibyśmy łatwo wstawić nasz przeanalizowany JSON do tabeli bazy danych.

I miałbyś rację.

Przygotowaliśmy go już z kolumnami i wierszami, a nawet nazwaliśmy kolumny i nadaliśmy im typy danych.

Teraz nadszedł czas, aby wstawić go do tabeli.

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   
    );

Wszystko, co zrobiłem, to dodanie INTO JsonCats do mojego zapytania, aby utworzyć tabelę o nazwie JsonCats i wstaw do niego wyniki zapytania.

Teraz wybierzmy zawartość tej tabeli.

SELECT * FROM JsonCats;

Wynik:

+----------+------------+--------+------------------------------------------------------+
| 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" }     |
+----------+------------+--------+------------------------------------------------------+

Zawartość jest dokładnie taka, jak widzieliśmy je we wcześniejszym przykładzie.

Aby mieć absolutną pewność, możemy teraz użyć sys.column widok katalogu systemowego sprawdź nazwy i typy kolumn tabeli.

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

Wynik:

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

Ponownie, dokładnie tak, jak to określiliśmy.

Zauważ, że sys.columns zawsze zwraca max_length z -1 gdy typ danych kolumny to varchar(max) , nvarchar(maks.) , zmienna (maks.) lub xml . Określiliśmy nvarchar(max) a więc wartość -1 jest dokładnie taki, jak oczekiwano.

Tryb ścieżki:luźny kontra rygorystyczny

Ścieżka podana w drugim argumencie lub w WITH klauzula może (opcjonalnie) zaczynać się od lax lub strict słowo kluczowe.

  • W lax tryb, OPENJSON() nie zgłasza błędu, jeśli nie można znaleźć obiektu lub wartości w określonej ścieżce. Jeśli nie można znaleźć ścieżki, OPENJSON() zwraca albo pusty zestaw wyników, albo NULL wartość.
  • W strict tryb, OPENJSON() zwraca błąd, jeśli nie można znaleźć ścieżki.

Domyślna wartość to lax , więc jeśli nie określisz trybu ścieżki, lax zostanie użyty tryb.

Oto kilka przykładów pokazujących, co dzieje się w każdym trybie, gdy nie można znaleźć ścieżki.

Drugi argument

W kolejnych dwóch przykładach podaję nieistniejącą ścieżkę w drugim argumencie podczas wywoływania metody OPENJSON() . Pierwszy przykład pokazuje, co się dzieje podczas korzystania z trybu lax, drugi przykład pokazuje, co dzieje się podczas korzystania z trybu ścisłego.

Tryb rozluźnienia

Oto, co dzieje się w lax tryb, gdy nie można znaleźć ścieżki.

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');

Wynik:

(0 rows affected)

Żaden błąd. Zwrócono tylko zero wyników.

Tryb ścisły

Teraz jest w strict tryb.

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');

Wynik:

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

Zgodnie z oczekiwaniami tryb ścisły spowodował błąd.

W klauzuli WITH

W kolejnych dwóch przykładach ponownie testujemy tryb lax vs tryb ścisły, z tym wyjątkiem, że tym razem określamy go w WITH klauzula podczas definiowania schematu.

Tryb rozluźnienia

Oto, co dzieje się w lax tryb.

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   
    );

Wynik:

+----------+------------+--------+------------------------------------------------------+
| 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" }     |
+----------+------------+--------+------------------------------------------------------+

W tym przypadku używam 'lax $.born' ponieważ próbuję odwołać się do klucza o nazwie born , ale taki klucz nie istnieje w JSON.

Tym razem kolumna, której nie można znaleźć, daje wynik NULL wartość.

Tryb ścisły

Teraz jest w strict tryb.

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   
    );

Wynik:

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

Tym razem użyłem 'strict $.born' .

Zgodnie z oczekiwaniami tryb ścisły spowodował błąd.

Poziom zgodności

OPENJSON() funkcja jest dostępna tylko na poziomie zgodności 130 lub wyższym.

Jeśli poziom zgodności Twojej bazy danych jest niższy niż 130, SQL Server nie będzie w stanie znaleźć i uruchomić OPENJSON() , a pojawi się błąd.

Możesz sprawdzić poziom zgodności bazy danych za pomocą sys.databases widok katalogu.

Możesz zmienić jego poziom zgodności w następujący sposób:

ALTER DATABASE DatabaseName 
SET COMPATIBILITY_LEVEL = 150;

Nowy w JSON?

Jeśli nie znasz się zbyt dobrze na JSON, zapoznaj się z moim samouczkiem JSON na Quackit.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. KWADRAT() Przykłady w SQL Server

  2. Co jest szybsze COALESCE CZY ISNULL?

  3. Plan wykonania SQL Server — co to jest i jak pomaga w problemach z wydajnością?

  4. Zmień typy kolumn w ogromnej tabeli

  5. Naruszenie ograniczenia UNIQUE KEY na INSERT WHERE COUNT(*) =0 w SQL Server 2005