Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Въведение в OPENJSON с примери (SQL Server)

SQL Server има функция с таблица, наречена OPENJSON() което създава релационен изглед на JSON данни.

Когато го извикате, предавате JSON документ като аргумент и OPENJSON() след това го анализира и връща обектите и свойствата на JSON документа в табличен формат – като редове и колони.

Пример

Ето един прост пример за демонстрация.

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

Резултат:

<пред>+-------+--------+-------+| ключ | стойност | тип ||-------+--------+-------|| 0 | Котка | 1 || 1 | Куче | 1 || 2 | Птица | 1 |+-------+--------+-------+

По подразбиране OPENJSON() връща таблица с три колони; ключ ,стойност , и тип .

Също така имате възможност да посочите своя собствена схема (което означава, че можете да дефинирате свои собствени колони). В моя прост пример използвах схемата по подразбиране и така бяха върнати трите колони по подразбиране.

Тези колони са дефинирани, както следва:

Колона Описание
ключ Съдържа името на посоченото свойство или индекса на елемента в посочения масив. Това е nvarchar(4000) стойност, а колоната има съпоставяне BIN2.
стойност Съдържа стойността на имота. Това е nvarchar(max) стойност, а колоната наследява своето съпоставяне от предоставения JSON.
тип Съдържа JSON типа на стойността. Това е представено като int стойност (от 0 до 5 ). Тази колона се връща само когато използвате схемата по подразбиране.

Типове по подразбиране

В света на JSON има шест типа данни. Това са низи ,номер , вярно/невярно (логично), нула ,обекта , имасив .

Когато анализирате някои JSON чрез OPENJSON() използвайки схемата по подразбиране, OPENJSON() определя какъв е типът JSON и след това попълва типа колона с int стойност, която представлява този тип.

Винт следователно стойността може да варира от 0 до 5 . Всяко вст стойност представлява тип JSON, както е посочено в следващата таблица.

Стойност в колоната „тип“ Тип данни JSON
0 нула
1 низ
2 номер
3 вярно/невярно
4 масив
5 обект

Следващият пример връща всичките шест от тези 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}]'); 

Резултат:

<пред>+-------+--------+-------+| ключ | стойност | тип ||-------+--------+-------|| име | NULL | 0 |+-------+--------+-------+(1 ред засегнат)+-------+----- ---+-------+| ключ | стойност | тип ||-------+--------+-------|| 0 | Котка | 1 || 1 | Куче | 1 || 2 | Птица | 1 |+-------+--------+-------+(3 засегнати реда)+-------+----- ---+-------+| ключ | стойност | тип ||-------+--------+-------|| 0 | 1 | 2 || 1 | 2 | 2 || 2 | 3 | 2 |+-------+--------+-------+(3 засегнати реда)+-------+----- ---+-------+| ключ | стойност | тип ||-------+--------+-------|| 0 | вярно | 3 || 1 | невярно | 3 |+-------+--------+-------+(2 засегнати реда)+-------+----- -------------------------------------------------- --+-------+| ключ | стойност | тип ||-------+--------------------------------------- -------------------+--------|| котки | [{ "id":1, "name":"Fluffy"},{ "id":2, "name":"Scratch"}] | 4 |+-------+--------------------------------------- ------------------+-------+(1 ред засегнат)+-------+------- --------------+-------+| ключ | стойност | тип ||-------+---------------------+-------|| 0 | {"A":1,"B":0,"C":1} | 5 |+-------+---------------------+-------+(1 ред засегнат)

Връщане на вложен 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 * FROM OPENJSON(@json, '$.pets.cats'); 

Резултат:

+-------+---------------------------------------------- ----------------+-------+| ключ | стойност | тип ||-------+--------------------------------------- ---------------+--------|| 0 | { "id" :1, "name" :"Fluffy", "sex" :"Female" } | 5 || 1 | { "id" :2, "name" :"Дълга опашка", "sex" :"Женски" } | 5 || 2 | { "id" :3, "name" :"Scratch", "sex" :"Male" } | 5 |+-------+------------------------------------------------ ---------------+--------+

В този случай посочих път на $.pets.cats , което доведе само до стойността на cats се връща. Стойността на котките е масив, така че целият масив е върнат.

За да върнем само една котка (т.е. един елемент от масива), можем да използваме синтаксиса на квадратни скоби за връщане на стойности на масива (като този $.pets.cats[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]'); 

Резултат:

+-------+----------+-------+| ключ | стойност | тип ||-------+----------+-------|| ID | 2 | 2 || име | Дълга опашка | 1 || секс | Жена | 1 |+-------+----------+-------+

Индексите на JSON масива са базирани на нула, така че този пример върна стойността на втория масив (защото посочих $.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   
    ); 

Резултат:

+----------+------------+-------+------------ -----------------------------------------+| Идентификатор на котка | Име на котка | Секс | Котки ||----------+------------+--------+-------------- ----------------------------------------|| 1 | Пухкави | Жена | { "id" :1, "name" :"Fluffy", "sex" :"Female" } || 2 | Дълга опашка | Жена | { "id" :2, "name" :"Дълга опашка", "sex" :"Женски" } || 3 | Надраскване | Мъжки | { "id" :3, "name" :"Scratch", "sex" :"Male" } |+----------+-----------+- -------+-------------------------------------------------- ------------+

Можем да видим, че имената на колоните отразяват тези, които посочих в WITH клауза. В тази клауза съпоставих всеки JSON ключ с моите собствени предпочитани имена на колони. Също така посочих типа данни на SQL Server, който искам за всяка колона.

Използвах също AS JSON на последната колона, за да върне тази колона като JSON фрагмент. Когато използвате КАТО 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
); 

Резултат:

+----------+--------------------+| име | system_type_name ||----------+--------------------|| Идентификатор на котка | int || Име на котка | varchar(60) || Секс | varchar(6) || Котки | 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; 

Резултат:

+----------+------------+-------+------------ -----------------------------------------+| Идентификатор на котка | Име на котка | Секс | Котки ||----------+------------+--------+-------------- ----------------------------------------|| 1 | Пухкави | Жена | { "id" :1, "name" :"Fluffy", "sex" :"Female" } || 2 | Дълга опашка | Жена | { "id" :2, "name" :"Дълга опашка", "sex" :"Женски" } || 3 | Надраскване | Мъжки | { "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; 

Резултат:

+---------+----------+--------------+| Колона | Тип | максимална_дължина ||----------+---------+--------------|| Идентификатор на котка | int | 4 || Име на котка | varchar | 60 || Секс | varchar | 6 || Котки | nvarchar | -1 |+---------+----------+--------------+

Отново, точно както го посочихме.

Обърнете внимание, че sys.columns винаги връща max_length от -1 когато типът данни на колоната е varchar(max) , nvarchar(max) ,варбинарна(макс.) , или xml . Посочихме nvarchar(max) и така стойността на -1 е точно както се очаква.

Режим на пътя:слаб срещу строг

Пътят, предоставен във втория аргумент или в WITH клаузата може (по избор) да започва с lax или strict ключова дума.

  • В lax режим, OPENJSON() не предизвиква грешка, ако обектът или стойността на посочения път не могат да бъдат намерени. Ако пътят не може да бъде намерен, OPENJSON() връща празен набор от резултати или NULL стойност.
  • В strict режим, OPENJSON() връща грешка, ако пътят не може да бъде намерен.

Стойността по подразбиране е lax , така че ако не посочите режим на пътя, lax ще се използва режим.

Ето няколко примера, които да демонстрират какво се случва с всеки режим, когато пътят не може да бъде намерен.

Втори аргумент

В следващите два примера предоставям несъществуващ път във втория аргумент при извикване на OPENJSON() . Първият пример показва какво се случва при използване на слаб режим, вторият пример показва какво се случва при използване на строг режим.

Лекав режим

Ето какво се случва в 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 засегнати реда)

Няма грешка. Върнаха само нула резултати.

Строк режим

Сега ето го в 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'); 

Резултат:

Съобщение 13608, ниво 16, състояние 3, ред 15 Свойството не може да бъде намерено на посочения JSON път.

Както се очакваше, строг режим доведе до грешка.

В клаузата WITH

В следващите два примера отново тестваме слаб режим срещу строг режим, с изключение на този път, че го указваме в 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   
    ); 

Резултат:

+----------+------------+-------+------------ -----------------------------------------+| Идентификатор на котка | Име на котка | Роден | Котки ||----------+------------+--------+-------------- ----------------------------------------|| 1 | Пухкави | NULL | { "id" :1, "name" :"Fluffy", "sex" :"Female" } || 2 | Дълга опашка | NULL | { "id" :2, "name" :"Дълга опашка", "sex" :"Женски" } || 3 | Надраскване | 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   
    ); 

Резултат:

Съобщение 13608, ниво 16, състояние 6, ред 16 Свойството не може да бъде намерено на посочения JSON път.

Този път използвах 'strict $.born' .

Както се очакваше, строг режим доведе до грешка.

Ниво на съвместимост

OPENJSON() функцията е достъпна само при ниво на съвместимост 130 или по-високо.

Ако нивото на съвместимост на вашата база данни е по-ниско от 130, SQL Server няма да може да намери и изпълни OPENJSON() , и ще получите грешка.

Можете да проверите нивото на съвместимост на вашата база данни чрез sys.databases изглед на каталог.

Можете да промените нивото на съвместимост по следния начин:

ALTER DATABASE DatabaseName 
SET COMPATIBILITY_LEVEL = 150; 

Нов сте в JSON?

Ако не сте толкова запознати с JSON, разгледайте моя урок за JSON в 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. SQL Server, подвеждащият XLOCK и оптимизации

  2. Трябва ли да използвам вградена колона varchar(max) или да я съхранявам в отделна таблица?

  3. Какъв е максималният брой знаци за NVARCHAR(MAX)?

  4. Проблем при отваряне на MDF файл, защото казва SQL грешка 5171? - Публикация за гост от Андре Уилямс

  5. Как да конвертирате изображение в масив от байтове, като използвате само javascript, за да съхранявате изображение на sql сървър?