Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Giới thiệu về OPENJSON với các ví dụ (SQL Server)

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ị 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ột
Mô 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 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.

mảng đối tượng
Giá trị trong cột “type” Kiểu dữ liệu JSON
0 null
1 chuỗi
2 số
3 đúng / sai
4
5

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ị 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ên JsonCats 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ằng lax hoặc strict 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ãy OPENJSON() trả về tập kết quả trống hoặc NULL 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.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Azure Data Studio là gì?

  2. Cách sử dụng SQL Server HierarchyID thông qua các ví dụ đơn giản

  3. Lọc theo Tùy chọn OFFSET-FETCH trong Truy vấn chọn - Hướng dẫn SQL Server / TSQL Phần 118

  4. Cách di chuyển tệp dữ liệu trong SQL Server - Phần 1

  5. Làm cách nào để đưa các giá trị rỗng vào MIN hoặc MAX?