SQL Server có một hàm giá trị bảng được gọi là OPENJSON()
tạo chế độ xem quan hệ của dữ liệu JSON.
Khi bạn gọi nó, bạn chuyển một tài liệu JSON làm đối số và OPENJSON()
sau đó phân tích cú pháp nó và trả về các đối tượng và thuộc tính của tài liệu JSON ở định dạng bảng - dưới dạng hàng và cột.
Ví dụ
Dưới đây là một ví dụ đơn giản để chứng minh.
SELECT * FROM OPENJSON('["Cat","Dog","Bird"]');
Kết quả:
+ ------- + --------- + -------- + | chìa khóa | giá trị | gõ || ------- + --------- + -------- || 0 | Con mèo | 1 || 1 | Con chó | 1 || 2 | Chim | 1 | + ------- + --------- + -------- +
Theo mặc định, OPENJSON()
trả về một bảng có ba cột; phím , giá trị và loại .
Bạn cũng có tùy chọn chỉ định lược đồ của riêng mình (có nghĩa là bạn có thể xác định các cột của riêng mình). Trong ví dụ đơn giản của tôi, tôi đã sử dụng lược đồ mặc định và do đó ba cột mặc định đã được trả về.
Các cột này được xác định như sau:
CộtMô tả | |
---|---|
key | Chứa tên của thuộc tính được chỉ định hoặc chỉ số của phần tử trong mảng được chỉ định. Đây là nvarchar (4000) và cột có đối chiếu BIN2. |
giá trị | Chứa giá trị của thuộc tính. Đây là nvarchar (tối đa) giá trị và cột kế thừa sự đối chiếu của nó từ JSON được cung cấp. |
loại | Chứa giá trị kiểu JSON. Điều này được biểu diễn dưới dạng int giá trị (từ 0 thành 5 ). Cột này chỉ được trả về khi bạn sử dụng lược đồ mặc định. |
Loại mặc định
Trong thế giới của JSON, có sáu kiểu dữ liệu. Đây là chuỗi , số , đúng / sai (boolean), null , đối tượng và mảng .
Khi bạn phân tích cú pháp một số JSON thông qua OPENJSON()
sử dụng lược đồ mặc định, OPENJSON()
tìm ra loại JSON là gì, sau đó điền vào loại cột có int giá trị đại diện cho loại đó.
int do đó giá trị có thể nằm trong khoảng từ 0
thành 5
. Mỗi int giá trị đại diện cho một loại JSON như được nêu trong bảng sau.
Giá trị trong cột “type” | Kiểu dữ liệu JSON |
---|---|
0 | null |
1 | chuỗi |
2 | số |
3 | đúng / sai |
4 | mảng|
5 | đối tượng
Ví dụ sau trả về tất cả sáu loại JSON này.
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}]');
Kết quả:
+ ------- + --------- + -------- + | chìa khóa | giá trị | gõ || ------- + --------- + -------- || tên | NULL | 0 | + ------- + --------- + -------- + (1 hàng bị ảnh hưởng) + ------- + ------ --- + -------- + | chìa khóa | giá trị | gõ || ------- + --------- + -------- || 0 | Con mèo | 1 || 1 | Con chó | 1 || 2 | Chim | 1 | + ------- + --------- + -------- + (3 hàng bị ảnh hưởng) + ------- + ------ --- + -------- + | chìa khóa | giá trị | gõ || ------- + --------- + -------- || 0 | 1 | 2 || 1 | 2 | 2 || 2 | 3 | 2 | + ------- + --------- + -------- + (3 hàng bị ảnh hưởng) + ------- + ------ --- + -------- + | chìa khóa | giá trị | gõ || ------- + --------- + -------- || 0 | sự thật | 3 || 1 | sai | 3 | + ------- + --------- + -------- + (2 hàng bị ảnh hưởng) + ------- + ------ -------------------------------------------------- - + -------- + | chìa khóa | giá trị | loại || ------- + --------------------------------------- ------------------- + -------- || mèo | [{"id":1, "name":"Fluffy"}, {"id":2, "name":"Scratch"}] | 4 | + ------- + --------------------------------------- ------------------- + -------- + (1 hàng bị ảnh hưởng) + ------- + ------- -------------- + -------- + | chìa khóa | giá trị | gõ || ------- + --------------------- + -------- || 0 | {"A":1, "B":0, "C":1} | 5 | + ------- + --------------------- + -------- + (1 hàng bị ảnh hưởng)Trả lại JSON lồng nhau
Bạn có thể trả về một đối tượng hoặc mảng lồng nhau bằng cách chỉ định đường dẫn của nó làm đối số thứ hai tùy chọn.
Nói cách khác, bạn không phải phân tích cú pháp toàn bộ tài liệu JSON - bạn có thể chọn chỉ phân tích cú pháp phần mà bạn quan tâm.
Đây là một ví dụ.
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');
Kết quả:
+ ------- + -------------------------------------- ---------------- + -------- + | chìa khóa | giá trị | loại || ------- + --------------------------------------- --------------- + -------- || 0 | {"id":1, "name":"Fluffy", "sex":"Female"} | 5 || 1 | {"id":2, "name":"Long Tail", "sex":"Female"} | 5 || 2 | {"id":3, "name":"Scratch", "sex":"Nam"} | 5 | + ------- + --------------------------------------- --------------- + -------- +Trong trường hợp này, tôi đã chỉ định một đường dẫn là
$.pets.cats
, điều này chỉ dẫn đến giá trị của mèo được trả lại. Giá trị của mèo là một mảng, vì vậy toàn bộ mảng đã được trả về.Để chỉ trả về một con mèo (tức là một phần tử mảng), chúng ta có thể sử dụng cú pháp dấu ngoặc vuông để trả về giá trị mảng (như sau
$.pets.cats[1]
).Dưới đây là cùng một ví dụ được sửa đổi để chỉ trả về một phần tử mảng:
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]');
Kết quả:
+ ------- + ----------- + -------- + | chìa khóa | giá trị | gõ || ------- + ----------- + -------- || id | 2 | 2 || tên | Đuôi dài | 1 || tình dục | Nữ | 1 | + ------- + ----------- + -------- +Chỉ mục mảng JSON dựa trên 0, vì vậy, ví dụ này trả về giá trị mảng thứ hai (vì tôi đã chỉ định
$.pets.cats[1]
).Nếu tôi đã chỉ định
$.pets.cats[0]
, giá trị đầu tiên sẽ được trả về (tức là con mèo có tên “Fluffy”).Xác định một lược đồ
Như đã đề cập, bạn có thể chỉ định lược đồ của riêng mình (tức là xác định các cột và kiểu của riêng bạn).
Đây là một ví dụ về việc đó.
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 );
Kết quả:
+ ---------- + ------------ + -------- + ------------- ----------------------------------------- + | Mã Mèo | Tên Mèo | Tình dục | Mèo || ---------- + ------------ + -------- + -------------- ---------------------------------------- || 1 | Bông xù | Nữ | {"id":1, "name":"Fluffy", "sex":"Female"} || 2 | Đuôi dài | Nữ | {"id":2, "name":"Long Tail", "sex":"Female"} || 3 | Cào | Nam | {"id":3, "name":"Scratch", "sex":"Nam"} | + ---------- + ------------ + - ------- + ------------------------------------------ ------------ +Chúng ta có thể thấy rằng các tên cột phản ánh những tên mà tôi đã chỉ định trong
WITH
mệnh đề. Trong mệnh đề đó, tôi đã ánh xạ từng khóa JSON với các tên cột ưa thích của riêng tôi. Tôi cũng đã chỉ định kiểu dữ liệu SQL Server mà tôi muốn cho mỗi cột.Tôi cũng đã sử dụng
AS JSON
trên cột cuối cùng để trả về cột đó dưới dạng phân đoạn JSON. Khi bạn sử dụng AS JSON, kiểu dữ liệu phải là nvarchar (max) .Xác minh các loại dữ liệu
Chúng ta có thể sử dụng truy vấn sau để xác minh các kiểu dữ liệu của mỗi cột.
Truy vấn này sử dụng
sys.dm_exec_describe_first_result_set
chế độ xem quản lý động hệ thống, trả về siêu dữ liệu về tập hợp kết quả đầu tiên từ một truy vấn.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 );
Kết quả:
+ ---------- + -------------------- + | tên | system_type_name || ---------- + -------------------- || Mã Mèo | int || Tên Mèo | varchar (60) || Tình dục | varchar (6) || Mèo | nvarchar (tối đa) | + ---------- + -------------------- +Chúng tôi có thể thấy rằng chúng hoàn toàn khớp với giản đồ của tôi.
Lưu ý rằng chìa khóa , giá trị và loại không có sẵn khi bạn xác định lược đồ của riêng mình. Các cột đó chỉ có sẵn khi sử dụng lược đồ mặc định.
Chèn JSON được phân tích cú pháp vào bảng
Bây giờ bạn có thể nghĩ rằng chúng tôi có thể dễ dàng chèn JSON đã phân tích cú pháp của mình vào một bảng cơ sở dữ liệu.
Và bạn đã đúng.
Chúng tôi đã chuẩn bị nó với các cột và hàng, và chúng tôi thậm chí đã đặt tên cho các cột và cung cấp cho chúng các kiểu dữ liệu.
Bây giờ đã đến lúc chèn nó vào bảng.
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 );
Tất cả những gì tôi đã làm là thêm
INTO JsonCats
vào truy vấn của tôi, để tạo một bảng có tênJsonCats
và chèn kết quả của truy vấn vào đó.Bây giờ chúng ta hãy chọn nội dung của bảng đó.
SELECT * FROM JsonCats;
Kết quả:
+ ---------- + ------------ + -------- + ------------- ----------------------------------------- + | Mã Mèo | Tên Mèo | Tình dục | Mèo || ---------- + ------------ + -------- + -------------- ---------------------------------------- || 1 | Bông xù | Nữ | {"id":1, "name":"Fluffy", "sex":"Female"} || 2 | Đuôi dài | Nữ | {"id":2, "name":"Long Tail", "sex":"Female"} || 3 | Cào | Nam | {"id":3, "name":"Scratch", "sex":"Nam"} | + ---------- + ------------ + - ------- + ------------------------------------------ ------------ +Nội dung chính xác như chúng ta đã thấy trong ví dụ trước đó.
Và để hoàn toàn chắc chắn, bây giờ chúng ta có thể sử dụng
sys.column
chế độ xem danh mục hệ thống kiểm tra tên và loại cột của bảng.SELECT name AS [Column], TYPE_NAME(system_type_id) AS [Type], max_length FROM sys.columns WHERE OBJECT_ID('JsonCats') = object_id;
Kết quả:
+ ---------- + ---------- + -------------- + | Cột | Loại | max_length || ---------- + ---------- + -------------- || Mã Mèo | int | 4 || Tên Mèo | varchar | 60 || Tình dục | varchar | 6 || Mèo | nvarchar | -1 | + ---------- + ---------- + -------------- +Một lần nữa, chính xác cách chúng tôi đã chỉ định nó.
Lưu ý rằng
sys.columns
luôn trả vềmax_length
trong tổng số-1
khi kiểu dữ liệu cột là varchar (max) , nvarchar (tối đa) , varbinary (max) hoặc xml . Chúng tôi đã chỉ định nvarchar (tối đa) và vì vậy giá trị của-1
chính xác như mong đợi.Chế độ đường dẫn:Dễ dàng so với Nghiêm ngặt
Đường dẫn được cung cấp trong đối số thứ hai hoặc trong
WITH
mệnh đề có thể (tùy chọn) bắt đầu bằnglax
hoặcstrict
từ khóa.
- Trong
lax
chế độ,OPENJSON()
không gây ra lỗi nếu không thể tìm thấy đối tượng hoặc giá trị trên đường dẫn được chỉ định. Nếu không thể tìm thấy đường dẫn, hãyOPENJSON()
trả về tập kết quả trống hoặcNULL
giá trị. - Trong
strict
chế độ,OPENJSON()
trả về lỗi nếu không tìm thấy đường dẫn.
Giá trị mặc định là lax
, vì vậy nếu bạn không chỉ định chế độ đường dẫn, hãy lax
chế độ sẽ được sử dụng.
Dưới đây là một số ví dụ để chứng minh điều gì xảy ra với mỗi chế độ khi không thể tìm thấy đường dẫn.
Đối số thứ hai
Trong hai ví dụ tiếp theo, tôi cung cấp một đường dẫn không tồn tại trong đối số thứ hai khi gọi OPENJSON()
. Ví dụ đầu tiên cho thấy điều gì sẽ xảy ra khi sử dụng chế độ lỏng lẻo, ví dụ thứ hai cho thấy điều gì sẽ xảy ra khi sử dụng chế độ nghiêm ngặt.
Chế độ Lax
Đây là những gì xảy ra trong lax
chế độ khi không thể tìm thấy đường dẫn.
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');
Kết quả:
(0 hàng bị ảnh hưởng)
Không có lỗi. Chỉ không trả về kết quả nào.
Chế độ nghiêm ngặt
Bây giờ ở đây nó ở trong strict
cách thức.
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');
Kết quả:
Msg 13608, Level 16, State 3, Line 15Property không thể tìm thấy trên đường dẫn JSON được chỉ định.
Như mong đợi, chế độ nghiêm ngặt đã dẫn đến lỗi.
Trong mệnh đề WITH
Trong hai ví dụ tiếp theo, chúng tôi lại kiểm tra chế độ lỏng lẻo so với chế độ nghiêm ngặt, ngoại trừ lần này chúng tôi chỉ định nó trong WITH
mệnh đề khi xác định lược đồ.
Chế độ Lax
Đây là những gì xảy ra trong lax
chế độ.
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
);
Kết quả:
+ ---------- + ------------ + -------- + ------------- ----------------------------------------- + | Mã Mèo | Tên Mèo | Sinh ra | Mèo || ---------- + ------------ + -------- + -------------- ---------------------------------------- || 1 | Bông xù | NULL | {"id":1, "name":"Fluffy", "sex":"Female"} || 2 | Đuôi dài | NULL | {"id":2, "name":"Long Tail", "sex":"Female"} || 3 | Cào | NULL | {"id":3, "name":"Scratch", "sex":"Nam"} | + ---------- + ------------ + - ------- + ------------------------------------------ ------------ +
Trong trường hợp này, tôi sử dụng 'lax $.born'
bởi vì tôi đang cố gắng tham chiếu một khóa có tên là born
, nhưng một khóa như vậy không tồn tại trong JSON.
Lần này, cột không thể tìm thấy dẫn đến NULL
giá trị.
Chế độ nghiêm ngặt
Bây giờ ở đây nó ở trong strict
chế độ.
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
);
Kết quả:
Msg 13608, Level 16, State 6, Line 16Property không thể tìm thấy trên đường dẫn JSON được chỉ định.
Lần này tôi đã sử dụng 'strict $.born'
.
Như mong đợi, chế độ nghiêm ngặt đã dẫn đến lỗi.
Mức độ tương thích
OPENJSON()
chức năng chỉ khả dụng ở mức độ tương thích 130 hoặc cao hơn.
Nếu mức độ tương thích cơ sở dữ liệu của bạn thấp hơn 130, SQL Server sẽ không thể tìm và chạy OPENJSON()
và bạn sẽ gặp lỗi.
Bạn có thể kiểm tra mức độ tương thích cơ sở dữ liệu của mình thông qua sys.databases
xem danh mục.
Bạn có thể thay đổi mức độ tương thích của nó như sau:
ALTER DATABASE DatabaseName
SET COMPATIBILITY_LEVEL = 150;
Bạn mới sử dụng JSON?
Nếu bạn chưa quen với JSON, hãy xem hướng dẫn JSON của tôi tại Quackit.