我正在T-SQL †中编写自定义JSON解析器。
出于解析器的目的,我使用的PATINDEX
功能是从标记列表中计算标记的位置。在我的情况下,标记都是单个字符,它们包括以下这些:
{} []:,
通常,当我需要找到几个给定字符中任何一个的(第一个)位置时,我会使用如下PATINDEX
函数:
PATINDEX('%[abc]%', SourceString)
然后,该函数将为我提供a
or b
或or 的第一个位置c
-两者中最先找到的那个SourceString
。
现在,就我而言,问题似乎与]
角色有关。一旦在字符列表中指定了它,例如:
PATINDEX('%[[]{}:,]%', SourceString)
我的预期模式显然已损坏,因为该函数从未找到匹配项。看来我需要一种方法来转义第一个,]
以便PATINDEX
将其视为查找字符之一,而不是特殊符号。
我发现这个问题询问类似的问题:
但是,在那种情况下,]
根本不需要在方括号中指定简单字符,因为它只是一个字符,可以在不带方括号的情况下进行指定。确实使用转义的替代解决方案仅针对LIKE
而不适用PATINDEX
,因为它使用了ESCAPE
由前者而非后者支持的子句。
所以,我的问题是,有没有什么办法去寻找一个]
与PATINDEX
使用[ ]
通配符?还是有一种方法可以使用其他Transact-SQL工具来模拟该功能?
附加信息
这是我需要PATINDEX
与上述[…]
模式一起使用的查询示例。这里的模式有效(尽管有点),因为它不包含]
字符。我也需要使用它]
:
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)
;
我得到的输出是:
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" }
您可以看到]
包含S
在其中一行的一部分中。该Level
列指示嵌套级别,表示括号和括号嵌套。正如你所看到的,一旦电平变2,它永远不会返回到1它将不得不如果我能把PATINDEX
识别]
作为标记。
上面的示例的预期输出为:
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" }
您可以在db <> fiddle上使用此查询。
†我们正在使用SQL Server 2014,不太可能很快升级到支持本地JSON解析的版本。我可以编写一个应用程序来完成这项工作,但是解析的结果需要进一步处理,这意味着应用程序中的工作不仅仅是解析-这种工作将更容易且可能更有效率地完成一个T-SQL脚本,如果我可以将其直接应用于结果的话。
我不太可能使用SQLCLR作为此问题的解决方案。但是,我不介意有人决定发布SQLCLR解决方案,因为这可能对其他人有用。
["foo]bar”]
呢?