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

Cách chọn JSON lồng nhau trong SQL Server với OPENJSON

Nếu bạn đang sử dụng OPENJSON() , nhưng bạn đang cố nhớ cách chọn một phần bên trong từ tài liệu JSON, hãy đọc tiếp.

OPENJSON() cú pháp cho phép bạn chuyển đổi tài liệu JSON thành dạng xem dạng bảng. Nó cũng cho phép bạn chọn một đoạn JSON lồng nhau từ tài liệu JSON.

Cách để làm điều này là với đường dẫn .

Đường dẫn

Đường dẫn bao gồm những điều sau:

  • Một ký hiệu đô la ($ ), đại diện cho mục ngữ cảnh.
  • Một tập hợp các bước đường dẫn. Các bước đường dẫn có thể chứa các phần tử và toán tử sau:
    • Tên chính. Ví dụ:$.pets$.pets.dogs . Nếu tên khóa bắt đầu bằng ký hiệu đô la hoặc chứa các ký tự đặc biệt như dấu cách, thì tên khóa phải được bao quanh bằng dấu ngoặc kép (ví dụ: $."my pets" ).
    • Các phần tử của mảng. Ví dụ:$.pets.dogs[1] . Chỉ mục của mảng dựa trên 0, vì vậy, ví dụ này chọn phần tử thứ hai trong mảng.
    • Toán tử dấu chấm (. ) chỉ ra một thành viên của một đối tượng. Ví dụ:trong $.pets.dogs , dogs là thành viên của pets .

Ví dụ cơ bản

Dưới đây là một ví dụ đơn giản để chứng minh.

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

Kết quả:

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

Trong trường hợp này, đối số thứ hai cho OPENJSON()'$.pets.dogs' , có nghĩa là chúng tôi đang chọn giá trị của dogs key, bản thân nó là con của pets .

Kí hiệu đô la ($ ) đại diện cho mục ngữ cảnh.

Lưu ý rằng trong ví dụ này, tôi cũng sử dụng WITH mệnh đề xác định lược đồ. Nếu tôi không bao gồm điều đó, lược đồ mặc định sẽ được sử dụng thay thế.

Đây là giao diện của nó khi sử dụng lược đồ mặc định.

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

Kết quả:

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

Vì vậy, chúng tôi vẫn đang chọn cùng một JSON lồng nhau, chỉ là chúng tôi đang sử dụng một giản đồ khác.

Lược đồ mặc định luôn trả về ba cột; phím , giá trị loại .

Chọn phần tử mảng

Như đã đề cập, bạn có thể sử dụng ký hiệu dấu ngoặc vuông để chọn một phần tử cụ thể trong một mảng.

Đâ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" : [
            { "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)
    );

Kết quả:

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

Xem như chỉ mục mảng dựa trên 0, chỉ định giá trị 0 trả về phần tử đầu tiên trong mảng.

Dưới đây là ví dụ này trông như thế nào khi sử dụng lược đồ mặc định (tức là không có WITH mệnh đề).

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

Kết quả:

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

Chế độ đường dẫn

Khi sử dụng đường dẫn, bạn có tùy chọn khai báo chế độ đường dẫn.

Chế độ đường dẫn xác định điều gì sẽ xảy ra khi biểu thức đường dẫn có lỗi.

Chế độ đường dẫn có thể là lax hoặc strict .

  • Trong lax , hàm trả về các giá trị trống nếu không tìm thấy đường dẫn. Ví dụ:nếu bạn yêu cầu giá trị $.pets.cows , nhưng JSON không chứa khóa đó, hàm trả về null, nhưng không phát sinh lỗi.
  • Trong strict , hàm này sẽ xảy ra lỗi nếu không tìm thấy đường dẫn.

Chế độ đường dẫn mặc định là lax , vì vậy nếu bạn không khai báo, hãy lax Được sử dụng.

Ví dụ

Dưới đây là một ví dụ để chứng minh cách mỗi chế độ đường dẫn xử lý các đường dẫn bị thiếu.

Chế độ 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" : [
            { "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');

Kết quả:

(0 rows affected)

Vì vậy, chế độ lỏng lẻo không gây ra bất kỳ lỗi nào. Nó chỉ dẫn đến không có hàng nào bị ảnh hưởng.

Nếu chúng tôi chỉ định lược đồ của riêng mình và chúng tôi đã chọn đúng đối tượng con, nhưng chúng tôi sử dụng một đường dẫn bị thiếu để ánh xạ tới tên cột, nó sẽ trả về NULL trong cột đó.

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

Kết quả:

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

Chế độ nghiêm ngặt

Đây là những gì sẽ xảy ra khi chúng tôi sử dụng chế độ nghiêm ngặt.

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

Kết quả:

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

Như mong đợi, nó đã dẫn đến lỗi.

Lỗi tương tự cũng xảy ra khi chúng tôi chọn đúng khóa JSON, nhưng ánh xạ một cột với một khóa không tồn tại.

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

Kết quả:

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

Đường dẫn trùng lặp

Nếu tài liệu JSON của bạn chứa các đường dẫn trùng lặp ở cùng mức lồng nhau, OPENJSON() có thể trả lại tất cả.

Điều này trái ngược với JSON_VALUE()JSON_QUERY() , cả hai đều chỉ trả về giá trị đầu tiên phù hợp với đường dẫn.

Đây là một ví dụ về việc sử dụng OPENJSON() để trả về các đường dẫn trùng lặp.

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

Kết quả:

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

Đối tượng con lồng nhau

Khi xác định lược đồ của riêng bạn, bạn có thể sử dụng AS JSON tùy chọn trả về toàn bộ đối tượng con dưới dạng tài liệu JSON của riêng 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" : [
            { "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
    );

Kết quả:

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

Nếu chúng tôi chưa sử dụng AS JSON tùy chọn, chúng tôi sẽ nhận được lỗi hoặc NULL, tùy thuộc vào việc chúng tôi có chỉ định lax hay không hoặc strict chế độ.

Đây là nó trong mỗi chế độ khi bỏ qua AS JSON tùy chọn.

Chế độ lỏng lẻo

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

Kết quả:

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

Chế độ nghiêm ngặt

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

Kết quả:

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. Thu thập dữ liệu tự động về các công việc đã hoàn thành trong MS SQL Server

  2. Mệnh đề SQL OVER () - khi nào và tại sao nó hữu ích?

  3. Đăng nhập không thành công cho người dùng 'DOMAIN \ MACHINENAME $'

  4. Bỏ tất cả các bảng có tên bắt đầu bằng một chuỗi nhất định

  5. TransactSQL để chạy một tập lệnh TransactSQL khác