T-SQL † özel bir JSON ayrıştırıcı yazıyorum .
Ayrıştırıcımın amacı için, PATINDEX
bir belirteç listesinden bir belirtecin konumunu hesaplayan işlevi kullanıyorum . Benim durumumdaki jetonların hepsi tek karakterdir ve şunları içerir:
{} []:,
Genellikle, verilen birkaç karakterden herhangi birinin (ilk) konumunu bulmam gerektiğinde, PATINDEX
işlevi şu şekilde kullanırım:
PATINDEX('%[abc]%', SourceString)
Fonksiyon sonra bana ilk konumunu verecektir a
ya b
ya c
içinde - ilk bulunabilir olur hangisi - SourceString
.
Şimdi benim durumumdaki problem ]
karakterle bağlantılı görünüyor . En kısa sürede karakter listesinde belirtmek gibi, örneğin:
PATINDEX('%[[]{}:,]%', SourceString)
fonksiyonum hiçbir zaman bir eşleşme bulamadığı için görünüşte kırıldım. İlkinden kaçmanın bir yoluna ihtiyacım var gibi görünüyor, ]
böylece PATINDEX
özel bir sembol yerine arama karakterlerinden biri olarak davranıyor.
Benzer bir sorun hakkında bu soruyu buldum:
Ancak, bu durumda, ]
parantez içinde basitçe belirtilmesi gerekmez, çünkü sadece bir karakterdir ve etraflarında parantez olmadan belirtilebilir. Kaçmayı kullanan alternatif çözüm, sadece için LIKE
değil , sadece için geçerlidir PATINDEX
, çünkü ESCAPE
birincisi tarafından desteklenir, ikincisi tarafından desteklenmez.
Yani, benim sorum, bir aramaya herhangi bir yolu yoktur ]
ile PATINDEX
kullanarak [ ]
joker? Veya diğer Transact-SQL araçlarını kullanarak bu işlevselliği taklit etmenin bir yolu var mı?
ek bilgi
Burada yukarıdaki gibi desen PATINDEX
ile kullanmanız gereken bir sorgu örneği […]
. Buradaki desen ( biraz da olsa ) çalışır, çünkü ]
karakteri içermez . Ben de çalışmak gerekiyor ]
:
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)
;
Aldığım çıktı:
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" }
Satırlardan birinde ]
parçası olarak dahil edildiğini görebilirsiniz S
. Level
Sütun, iç içe braket anlam ve parantez iç içe seviyesini gösterir. Gördüğünüz gibi, seviye 2 olduğunda, asla 1'e dönmez . Bir token olarak PATINDEX
tanımayı yapabilseydim olurdu ]
.
Yukarıdaki örnek için beklenen çıktı:
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" }
Bu sorgu ile db <> fiddle'da oynayabilirsiniz .
† SQL Server 2014 kullanıyoruz ve yakında yerel olarak JSON ayrıştırmayı destekleyen bir sürüme yükseltme olasılığı düşük. İşi yapmak için bir başvuru yazabilirim ancak ayrıştırma sonuçlarının daha fazla işlenmesi gerekir, bu da uygulamada yalnızca ayrıştırmadan daha fazla iş anlamına gelir - çok daha kolay ve muhtemelen daha verimli bir şekilde yapılacak bir iş bir T-SQL betiği, yalnızca doğrudan sonuçlara uygularsam.
SQLCLR'yi bu soruna bir çözüm olarak kullanabilmem pek olası değildir. Ancak, birisinin bir SQLCLR çözümü yayınlamaya karar verip vermediğini umursamıyorum, çünkü bu diğerleri için yararlı olabilir.
["foo]bar”]
?