Ich schreibe einen benutzerdefinierten JSON-Parser in T-SQL † .
Für den Zweck meines Parsers verwende ich die PATINDEX
Funktion, die die Position eines Tokens aus einer Liste von Token berechnet. Die Token in meinem Fall sind alle Einzelzeichen und enthalten Folgendes:
{} []:,
Wenn ich die (erste) Position eines von mehreren gegebenen Zeichen finden muss, verwende ich normalerweise die folgende PATINDEX
Funktion:
PATINDEX('%[abc]%', SourceString)
Die Funktion gibt mir dann die erste Position von a
oder b
oder c
- je nachdem, was zuerst gefunden wird - in SourceString
.
Jetzt scheint das Problem in meinem Fall mit dem ]
Charakter verbunden zu sein. Sobald ich es in der Zeichenliste spezifiziere, zB so:
PATINDEX('%[[]{}:,]%', SourceString)
Mein beabsichtigtes Muster wird anscheinend gebrochen, weil die Funktion nie eine Übereinstimmung findet. Es sieht ]
so aus, PATINDEX
als ob ich einen Weg brauche, um dem ersten zu entkommen, damit er als eines der Suchzeichen und nicht als spezielles Symbol behandelt wird.
Ich habe diese Frage zu einem ähnlichen Problem gefunden:
In diesem Fall muss das ]
einfach nicht in Klammern angegeben werden, da es nur ein Zeichen ist und ohne Klammern angegeben werden kann. Die alternative Lösung, die Escape verwendet, funktioniert nur für LIKE
und nicht für PATINDEX
, da sie einen ESCAPE
Unterabschnitt verwendet, der von der ersteren und nicht von der letzteren unterstützt wird.
Meine Frage ist also, gibt es eine Möglichkeit, ]
mit PATINDEX
dem [ ]
Platzhalter nach einem zu suchen ? Oder gibt es eine Möglichkeit, diese Funktionalität mit anderen Transact-SQL-Tools zu emulieren?
zusätzliche Information
Hier ist ein Beispiel für eine Abfrage, bei der ich PATINDEX
das […]
Muster wie oben verwenden muss. Das Muster hier funktioniert (wenn auch etwas ), weil es das ]
Zeichen nicht enthält . Ich brauche es auch, um damit zu arbeiten ]
:
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)
;
Die Ausgabe, die ich bekomme, ist:
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" }
Sie können sehen, dass das ]
als Teil von S
in einer der Zeilen enthalten ist. Die Level
Spalte gibt die Verschachtelungsebene an, dh die Verschachtelung von Klammern und Klammern. Wie Sie sehen können, sobald die Stufe 2 wird, gibt es nie zu 1. Es wäre, wenn ich machen könnte PATINDEX
erkennen , ]
als Zeichen.
Die erwartete Ausgabe für das obige Beispiel lautet:
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" }
Sie können mit dieser Abfrage bei db <> fiddle spielen .
† Wir verwenden SQL Server 2014 und werden wahrscheinlich nicht bald auf eine Version aktualisieren, die JSON-Parsing nativ unterstützt. Ich könnte eine Anwendung schreiben, um die Arbeit zu erledigen, aber die Ergebnisse der Analyse müssen weiter verarbeitet werden, was mehr Arbeit in der Anwendung als nur die Analyse bedeutet - die Art von Arbeit, die viel einfacher und wahrscheinlich effizienter erledigt werden würde ein T-SQL-Skript, wenn ich es nur direkt auf die Ergebnisse anwenden könnte.
Es ist sehr unwahrscheinlich, dass ich SQLCLR als Lösung für dieses Problem verwenden kann. Es macht mir jedoch nichts aus, wenn sich jemand entscheidet, eine SQLCLR-Lösung zu veröffentlichen, da dies für andere nützlich sein könnte.
["foo]bar”]
?