T-SQL † özel bir JSON ayrıştırıcı yazıyorum .
Ayrıştırıcımın amacı için, PATINDEXbir 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, PATINDEXişlevi şu şekilde kullanırım:
PATINDEX('%[abc]%', SourceString)
Fonksiyon sonra bana ilk konumunu verecektir aya bya ciç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 LIKEdeğil , sadece için geçerlidir PATINDEX, çünkü ESCAPEbirincisi tarafından desteklenir, ikincisi tarafından desteklenmez.
Yani, benim sorum, bir aramaya herhangi bir yolu yoktur ]ile PATINDEXkullanarak [ ]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 PATINDEXile 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. LevelSü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 PATINDEXtanı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”]?