J'écris un analyseur JSON personnalisé en T-SQL † .
Aux fins de mon analyseur, j'utilise la PATINDEX
fonction qui calcule la position d'un jeton à partir d'une liste de jetons. Les jetons dans mon cas sont tous des caractères uniques et ils comprennent ceux-ci:
{} []:,
Habituellement, lorsque j'ai besoin de trouver la (première) position de l'un des caractères donnés, j'utilise la PATINDEX
fonction comme ceci:
PATINDEX('%[abc]%', SourceString)
La fonction me donnera alors la première position de a
ou b
ou c
- selon ce qui se trouve en premier - dans SourceString
.
Maintenant, le problème dans mon cas semble être lié au ]
personnage. Dès que je le précise dans la liste des personnages, par exemple comme ceci:
PATINDEX('%[[]{}:,]%', SourceString)
mon modèle prévu devient apparemment cassé, car la fonction ne trouve jamais de correspondance. Il semble que j'ai besoin d'un moyen d'échapper au premier, ]
ce qui le PATINDEX
traite comme l'un des caractères de recherche plutôt que comme un symbole spécial.
J'ai trouvé cette question posant sur un problème similaire:
Cependant, dans ce cas, le ]
simplement n'a pas besoin d'être spécifié entre crochets, car il s'agit d'un seul caractère et il peut être spécifié sans crochets autour d'eux. La solution alternative, qui utilise l'échappement, ne fonctionne que pour LIKE
et non pour PATINDEX
, car elle utilise un ESCAPE
sous-paragraphe, pris en charge par le premier et non par le second.
Donc, ma question est, existe-t-il un moyen de rechercher un ]
avec l' PATINDEX
utilisation du [ ]
caractère générique? Ou existe-t-il un moyen d'émuler cette fonctionnalité à l'aide d'autres outils Transact-SQL?
Information additionnelle
Voici un exemple de requête que je dois utiliser PATINDEX
avec le […]
modèle ci-dessus. Le modèle ici fonctionne (quoique quelque peu ) car il n'inclut pas le ]
personnage. J'en ai aussi besoin pour travailler avec ]
:
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)
;
La sortie que j'obtiens est:
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" }
Vous pouvez voir que le ]
est inclus dans le cadre de l' S
une des lignes. La Level
colonne indique le niveau d'imbrication, c'est-à-dire l'imbrication des crochets et des accolades. Comme vous pouvez le voir, une fois que le niveau devient 2, il ne revient jamais à 1. Il l'aurait fait si je pouvais faire PATINDEX
reconnaître ]
comme un jeton.
La sortie attendue pour l'exemple ci-dessus est:
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" }
Vous pouvez jouer avec cette requête sur db <> fiddle .
† Nous utilisons SQL Server 2014 et il est peu probable que nous procédions à une mise à niveau prochaine vers une version qui prend en charge l'analyse JSON en natif. Je pourrais écrire une application pour faire le travail mais les résultats de l'analyse doivent être traités plus loin, ce qui implique plus de travail dans l'application que simplement l'analyse - le type de travail qui serait beaucoup plus facile, et probablement plus efficace, effectué avec un script T-SQL, si seulement je pouvais l'appliquer directement aux résultats.
Il est très peu probable que je puisse utiliser SQLCLR comme solution à ce problème. Cependant, cela ne me dérange pas si quelqu'un décide de publier une solution SQLCLR, car cela pourrait être utile pour d'autres.
["foo]bar”]
?