Tôi viết một phân tích cú pháp JSON tùy chỉnh trong T-SQL † .
Với mục đích của trình phân tích cú pháp của tôi, tôi đang sử dụng PATINDEX
chức năng tính toán vị trí của mã thông báo từ danh sách mã thông báo. Các mã thông báo trong trường hợp của tôi đều là các ký tự đơn và chúng bao gồm:
{} [] :,
Thông thường, khi tôi cần tìm vị trí (đầu tiên) của bất kỳ ký tự nào, tôi sử dụng PATINDEX
hàm như thế này:
PATINDEX('%[abc]%', SourceString)
Hàm sau đó sẽ cho tôi vị trí đầu tiên của a
hoặc b
hoặc c
- bất kỳ trường hợp nào được tìm thấy trước - trong SourceString
.
Bây giờ vấn đề trong trường hợp của tôi dường như được kết nối với ]
nhân vật. Ngay sau khi tôi chỉ định nó trong danh sách nhân vật, ví dụ như thế này:
PATINDEX('%[[]{}:,]%', SourceString)
mô hình dự định của tôi dường như bị phá vỡ, bởi vì chức năng không bao giờ tìm thấy một kết quả khớp. Có vẻ như tôi cần một cách để thoát khỏi cái đầu tiên ]
để PATINDEX
coi nó như một trong những nhân vật tra cứu hơn là một biểu tượng đặc biệt.
Tôi đã tìm thấy câu hỏi này hỏi về một vấn đề tương tự:
Tuy nhiên, trong trường hợp đó, ]
đơn giản là không cần phải được chỉ định trong ngoặc, bởi vì nó chỉ là một ký tự và nó có thể được chỉ định mà không có dấu ngoặc quanh chúng. Giải pháp thay thế, sử dụng thoát, chỉ hoạt động cho LIKE
và không PATINDEX
sử dụng, bởi vì nó sử dụng một phần ESCAPE
phụ, được hỗ trợ bởi cái trước chứ không phải cái sau.
Vì vậy, câu hỏi của tôi là, có cách nào để tìm kiếm ]
bằng PATINDEX
cách sử dụng [ ]
ký tự đại diện không? Hoặc có cách nào để mô phỏng chức năng đó bằng các công cụ Transact-SQL khác không?
thông tin thêm
Dưới đây là một ví dụ về truy vấn mà tôi cần sử dụng PATINDEX
với […]
mẫu như trên. Các mô hình ở đây hoạt động (mặc dù phần nào ) bởi vì nó không bao gồm các ]
nhân vật. Tôi cũng cần nó để làm việc với ]
:
WITH
data AS (SELECT CAST('{"f1":["v1","v2"],"f2":"v3"}' AS varchar(max)) AS ResponseJSON),
parser AS
(
SELECT
Level = 1,
OpenClose = 1,
P = p.P,
S = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
C = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1),
ResponseJSON = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
FROM
data AS d
CROSS APPLY (SELECT PATINDEX('%[[{]%', d.ResponseJSON)) AS p (P)
UNION ALL
SELECT
Level = ISNULL(d.OpenClose - 1, 0) + d.Level + ISNULL(oc.OpenClose, 0),
OpenClose = oc.OpenClose,
P = d.P + p.P,
S = SUBSTRING(d.ResponseJSON, 1, NULLIF(p.P, 0) - 1),
C = c.C,
ResponseJSON = SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0) + 1, 999999)
FROM
parser AS d
CROSS APPLY (SELECT PATINDEX('%[[{}:,]%' COLLATE Latin1_General_BIN2, d.ResponseJSON)) AS p (P)
CROSS APPLY (SELECT SUBSTRING(d.ResponseJSON, NULLIF(p.P, 0), 1)) AS c (C)
CROSS APPLY (SELECT CASE WHEN c.C IN ('[', '{') THEN 1 WHEN c.C IN (']', '}') THEN 0 END) AS oc (OpenClose)
WHERE 1=1
AND p.P <> 0
)
SELECT
*
FROM
parser
OPTION
(MAXRECURSION 0)
;
Đầu ra tôi nhận được là:
Level OpenClose P S C ResponseJSON
----- --------- -- ----- -- ---------------------------
1 1 1 { "f1":["v1","v2"],"f2":"v3"}
1 null 6 "f1" : ["v1","v2"],"f2":"v3"}
2 1 7 [ "v1","v2"],"f2":"v3"}
2 null 12 "v1" , "v2"],"f2":"v3"}
2 null 18 "v2"] , "f2":"v3"}
2 null 23 "f2" : "v3"}
2 0 28 "v3" }
Bạn có thể thấy rằng nó ]
được bao gồm như là một phần của S
một trong các hàng. Các Level
cột chỉ ra mức độ làm tổ, có nghĩa là khung và niềng răng làm tổ. Như bạn có thể thấy, một khi cấp độ trở thành 2, nó sẽ không bao giờ trở lại 1. Nó sẽ có nếu tôi có thể PATINDEX
nhận ra ]
là mã thông báo.
Đầu ra dự kiến cho ví dụ trên là:
Level OpenClose P S C ResponseJSON
----- --------- -- ---- -- ---------------------------
1 1 1 { "f1":["v1","v2"],"f2":"v3"}
1 NULL 6 "f1" : ["v1","v2"],"f2":"v3"}
2 1 7 [ "v1","v2"],"f2":"v3"}
2 NULL 12 "v1" , "v2"],"f2":"v3"}
2 0 17 "v2" ] ,"f2":"v3"}
1 NULL 18 , "f2":"v3"}
1 NULL 23 "f2" : "v3"}
1 0 28 "v3" }
Bạn có thể chơi với truy vấn này tại db <> fiddle .
† Chúng tôi đang sử dụng SQL Server 2014 và không có khả năng sớm nâng cấp lên một phiên bản hỗ trợ JSON phân tích nguyên bản. Tôi có thể viết một ứng dụng để thực hiện công việc nhưng kết quả của việc phân tích cú pháp cần được xử lý thêm, điều này hàm ý nhiều công việc trong ứng dụng hơn là phân tích cú pháp - loại công việc sẽ dễ dàng hơn và có thể hiệu quả hơn, được thực hiện với một tập lệnh T-SQL, nếu chỉ tôi có thể áp dụng nó trực tiếp vào kết quả.
Rất khó có khả năng tôi có thể sử dụng SQLCLR làm giải pháp cho vấn đề này. Tuy nhiên, tôi không phiền nếu ai đó quyết định đăng một giải pháp SQLCLR, vì điều đó có thể hữu ích cho những người khác.
["foo]bar”]
nào?