T-SQL † 에서 사용자 지정 JSON 파서를 작성 중 입니다.
파서의 목적을 PATINDEX
위해 토큰 목록에서 토큰의 위치를 계산하는 함수를 사용하고 있습니다. 필자의 경우 토큰은 모두 단일 문자이며 다음을 포함합니다.
{} [] :,
일반적으로 주어진 여러 문자 중 첫 번째 위치를 찾아야 할 때 다음 PATINDEX
과 같은 기능을 사용합니다 .
PATINDEX('%[abc]%', SourceString)
이 기능은 다음 날의 첫 번째 위치 줄 것이다 a
또는 b
나 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”]
습니까?