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

Jak wybrać zagnieżdżony JSON w SQL Server za pomocą OPENJSON

Jeśli używasz OPENJSON() , ale próbujesz zapamiętać, jak wybrać wewnętrzny fragment z dokumentu JSON, czytaj dalej.

OPENJSON() składnia umożliwia konwersję dokumentów JSON na widok tabelaryczny. Pozwala również wybrać zagnieżdżony fragment JSON z dokumentu JSON.

Sposobem na to jest użycie ścieżek .

Ścieżki

Ścieżka składa się z następujących elementów:

  • Znak dolara ($ ), który reprezentuje element kontekstu.
  • Zestaw kroków ścieżki. Kroki ścieżki mogą zawierać następujące elementy i operatory:
    • Nazwy kluczy. Na przykład $.pets i $.pets.dogs . Jeśli nazwa klucza zaczyna się od znaku dolara lub zawiera znaki specjalne, takie jak spacje, musi być otoczona cudzysłowami (na przykład $."my pets" ).
    • Elementy tablicy. Na przykład $.pets.dogs[1] . Indeksy tablicy są liczone od zera, więc ten przykład wybiera drugi element tablicy.
    • Operator kropki (. ) wskazuje członka obiektu. Na przykład w $.pets.dogs , dogs jest członkiem pets .

Przykład podstawowy

Oto prosty przykład do zademonstrowania.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs')
WITH  (
        [id]    int,  
        [name]  varchar(60), 
        [sex]   varchar(6)
    );

Wynik:

+------+--------+--------+
| id   | name   | sex    |
|------+--------+--------|
| 1    | Fetch  | Male   |
| 2    | Fluffy | Male   |
| 3    | Wag    | Female |
+------+--------+--------+

W tym przypadku drugi argument OPENJSON() to '$.pets.dogs' , co oznacza, że ​​wybieramy wartość dogs klucz, który sam jest dzieckiem pets .

Znak dolara ($ ) reprezentuje element kontekstu.

Zauważ, że w tym przykładzie używam również WITH klauzula definiująca schemat. Gdybym tego nie uwzględnił, zamiast tego zostałby użyty domyślny schemat.

Oto jak to wygląda przy użyciu domyślnego schematu.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs');

Wynik:

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

Więc nadal wybieramy ten sam zagnieżdżony JSON, po prostu używamy innego schematu.

Domyślny schemat zawsze zwraca trzy kolumny; klucz , wartość i wpisz .

Wybieranie elementów tablicy

Jak wspomniano, możesz użyć notacji z nawiasami kwadratowymi, aby wybrać określony element w tablicy.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]')
WITH  (
        [id]    int,  
        [name]  varchar(60), 
        [sex]   varchar(6)
    );

Wynik:

+------+--------+-------+
| id   | name   | sex   |
|------+--------+-------|
| 1    | Fetch  | Male  |
+------+--------+-------+

Ponieważ indeksy tablic są liczone od zera, określając wartość 0 zwraca pierwszy element tablicy.

Oto jak wygląda ten przykład przy użyciu domyślnego schematu (tj. bez WITH klauzula).

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets.dogs[0]');

Wynik:

+-------+---------+--------+
| key   | value   | type   |
|-------+---------+--------|
| id    | 1       | 2      |
| name  | Fetch   | 1      |
| sex   | Male    | 1      |
+-------+---------+--------+

Tryb ścieżki

Podczas korzystania ze ścieżek masz możliwość zadeklarowania trybu ścieżki.

Tryb ścieżki określa, co się stanie, gdy wyrażenie ścieżki zawiera błąd.

Tryb ścieżki może być lax lub strict .

  • W lax w trybie, funkcja zwraca puste wartości, jeśli nie można znaleźć ścieżki. Na przykład, jeśli zażądasz wartości $.pets.cows , ale JSON nie zawiera tego klucza, funkcja zwraca wartość null, ale nie zgłasza błędu.
  • W strict w trybie, funkcja zgłasza błąd, jeśli nie można znaleźć ścieżki.

Domyślny tryb ścieżki to lax , więc jeśli tego nie zadeklarujesz, lax Jest używane.

Przykład

Oto przykład pokazujący, jak każdy tryb ścieżki obsługuje brakujące ścieżki.

Tryb rozluźnienia

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'lax $.pets.cows');

Wynik:

(0 rows affected)

Tak więc tryb lax nie wyrzucił żadnych błędów. Spowodowało to po prostu brak wpływu na zero wierszy.

Gdybyśmy określili nasz własny schemat i wybrali poprawny podobiekt, ale użyliśmy brakującej ścieżki do mapowania na nazwę kolumny, zwróciłoby to NULL w tej kolumnie.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}'

SELECT *
FROM OPENJSON(@json, 'lax $.pets.dogs')
WITH  (
        [id]    int         'lax $.id',  
        [name]  varchar(60) 'lax $.name', 
        [color]   varchar(6)  'lax $.color'
    );

Wynik:

+------+--------+---------+
| id   | name   | color   |
|------+--------+---------|
| 1    | Fetch  | NULL    |
| 2    | Fluffy | NULL    |
| 3    | Wag    | NULL    |
+------+--------+---------+

Tryb ścisły

Oto, co się dzieje, gdy używamy trybu ścisłego.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'strict $.pets.cows');

Wynik:

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

Zgodnie z oczekiwaniami spowodowało to błąd.

Ten sam błąd występuje, gdy wybieramy poprawny klucz JSON, ale mapujemy kolumnę na nieistniejący klucz.

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, 'strict $.pets.dogs')
WITH  (
        [id]    int         'strict $.id',  
        [name]  varchar(60) 'strict $.name', 
        [color]   varchar(6)  'strict $.color'
    );

Wynik:

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

Zduplikowane ścieżki

Jeśli Twój dokument JSON zawiera zduplikowane ścieżki na tym samym poziomie zagnieżdżenia, OPENJSON() może zwrócić je wszystkie.

Jest to w przeciwieństwie do JSON_VALUE() i JSON_QUERY() , z których oba zwracają tylko pierwszą wartość, która pasuje do ścieżki.

Oto przykład użycia OPENJSON() aby zwrócić zduplikowane ścieżki.

DECLARE @json NVARCHAR(4000) = N'{
    "dog": {
            "names": {
                "name": "Fetch", 
                "name": "Good Dog"
            }
        }
    }';
SELECT * FROM OPENJSON(@json, '$.dog.names');

Wynik:

+-------+----------+--------+
| key   | value    | type   |
|-------+----------+--------|
| name  | Fetch    | 1      |
| name  | Good Dog | 1      |
+-------+----------+--------+

Zagnieżdżone obiekty podrzędne

Podczas definiowania własnego schematu możesz użyć AS JSON możliwość zwrócenia całego podobiektu jako własnego dokumentu 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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) '$.dogs' AS JSON
    );

Wynik:

+--------+
| dogs   |
|--------|
| [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]        |
+--------+

Gdybyśmy nie użyli AS JSON opcja, otrzymalibyśmy błąd lub NULL, w zależności od tego, czy określiliśmy lax lub strict tryb.

Tutaj jest w każdym trybie z pominięciem AS JSON opcja.

Tryb rozluźnienia

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) 'lax $.dogs'
    );

Wynik:

+--------+
| dogs   |
|--------|
| NULL   |
+--------+

Tryb ścisły

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" : [
            { "id" : 1, "name" : "Fetch", "sex" : "Male" },
            { "id" : 2, "name" : "Fluffy", "sex" : "Male" },
            { "id" : 3, "name" : "Wag", "sex" : "Female" }
        ]
    }
}';

SELECT *
FROM OPENJSON(@json, '$.pets')
WITH  (
        [dogs]  nvarchar(max) 'strict $.dogs'
    );

Wynik:

Msg 13624, Level 16, State 1, Line 16
Object or array cannot be found in the specified JSON path.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Brak wsparcia dla OVER w MS SQL Server 2005?

  2. Jak łatwo i szybko sparametryzować ciąg o wartości null za pomocą DBNull.Value?

  3. Jak znaleźć katalog danych dla instancji SQL Server?

  4. SSMS wersja 18 – brak diagramów bazy danych

  5. Jak naprawić błąd „Dostawca nazwanych potoków, błąd 40 — nie można otworzyć połączenia z serwerem SQL Server”?