최신 정보:
@ Mikael 's fine answer 에 대한 의견에 명시된 최신 요구 사항을 반영하기 위해 아래 예제 쿼리의 입력 및 출력 XML뿐만 아니라 코드를 업데이트했습니다 .
@Value가 비어 있거나 존재하지 않는 경우 Value 요소를 만들지 않습니다.
단일 표현식이이 새로운 변형과 정확하게 일치 할 수 있지만 <Value/>
, 대체 문자열에서 조건부 논리가 허용되지 않으므로 단일 패스에서 빈 요소 를 생략 할 수있는 방법 이 없습니다. 그래서 나는 이것을 두 부분으로 수정했습니다. 하나 @Value
는 비어 있지 않은 @Value
속성 을 얻는 패스와 하나는 빈 속성 을 얻는 패스 입니다. 어쨌든 요소를 갖지 않기를 원 <Element>
하므로 @Value
속성이 누락 된 을 처리 할 필요가 없었 <Value>
습니다.
한 가지 옵션은 XML을 일반 문자열로 취급하고 패턴을 기반으로 변환하는 것입니다. 이는 SQLCLR 코드를 통해 사용할 수있는 정규식 (특히 "바꾸기"기능)을 사용하여 쉽게 수행 할 수 있습니다.
아래 예제 는 SQL # 라이브러리 의 RegEx_Replace 스칼라 UDF를 사용합니다 (저는 필자이지만이 RegEx 함수는 다른 버전과 함께 무료 버전으로 제공됩니다).
DECLARE @SomeXml XML;
SET @SomeXml = N'<Root attr1="val1" attr2="val2">
<Elements>
<Element Code="1" Value="aaa" ExtraData="extra1" />
<Element Code="22" Value="bbb" ExtraData="extra2" />
<Element Code="333" Value="ccc" ExtraData="extra3" />
<Element Code="4444" Value="" ExtraData="extra4" />
<Element Code="55555" ExtraData="extra5" />
</Elements>
<ExtraData>
<Something Val="1">qwerty A</Something>
<Something Val="2">qwerty B</Something>
</ExtraData>
</Root>';
DECLARE @TempStringOfXml NVARCHAR(MAX),
@Expression NVARCHAR(4000),
@Replacement NVARCHAR(4000);
SET @TempStringOfXml = CONVERT(NVARCHAR(MAX), @SomeXml);
PRINT N'Original: ' + @TempStringOfXml;
---
SET @Expression =
N'(<Element Code="[^"]+")\s+Value="([^"]+)"\s+(ExtraData="[^"]+")\s*/>';
SET @Replacement = N'$1 $3><Value>$2</Value></Element>';
SELECT @TempStringOfXml = SQL#.RegEx_Replace(@TempStringOfXml, @Expression,
@Replacement, -1, 1, '');
PRINT '-------------------------------------';
PRINT N'Phase 1: ' + @TempStringOfXml; -- transform Elements with a non-empty @Value
---
SET @Expression = N'(<Element Code="[^"]+")\s+Value=""\s+(ExtraData="[^"]+")\s*/>';
SET @Replacement = N'$1 $2 />';
SELECT @TempStringOfXml = SQL#.RegEx_Replace(@TempStringOfXml, @Expression,
@Replacement, -1, 1, '');
PRINT '-------------------------------------';
PRINT N'Phase 2: ' + @TempStringOfXml; -- transform Elements with an empty @Value
SELECT CONVERT(XML, @TempStringOfXml); -- prove that this is valid XML
PRINT
문은 "메시지"탭에서 쉽게 나란히 비교가 수 있도록하고 있습니다. 결과 출력은 다음과 같습니다 (원하는 XML 만 약간 수정하여 원하는 부분 만 만지고 다른 부분은 없음을 분명히했습니다).
Original: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" Value="aaa" ExtraData="extra1"/><Element Code="22" Value="bbb" ExtraData="extra2"/><Element Code="333" Value="ccc" ExtraData="extra3"/><Element Code="4444" Value="" ExtraData="extra4"/><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
-------------------------------------
Phase 1: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" ExtraData="extra1"><Value>aaa</Value></Element><Element Code="22" ExtraData="extra2"><Value>bbb</Value></Element><Element Code="333" ExtraData="extra3"><Value>ccc</Value></Element><Element Code="4444" Value="" ExtraData="extra4"/><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
-------------------------------------
Phase 2: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" ExtraData="extra1"><Value>aaa</Value></Element><Element Code="22" ExtraData="extra2"><Value>bbb</Value></Element><Element Code="333" ExtraData="extra3"><Value>ccc</Value></Element><Element Code="4444" ExtraData="extra4" /><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
테이블의 필드를 업데이트하려는 경우 위의 내용을 다음과 같이 조정할 수 있습니다.
DECLARE @NonEmptyValueExpression NVARCHAR(4000),
@NonEmptyValueReplacement NVARCHAR(4000),
@EmptyValueExpression NVARCHAR(4000),
@EmptyValueReplacement NVARCHAR(4000);
SET @NonEmptyValueExpression =
N'(<Element Code="[^"]+")\s+Value="([^"]+)"\s+(ExtraData="[^"]+")\s*/>';
SET @NonEmptyValueReplacement = N'$1 $3><Value>$2</Value></Element>';
SET @EmptyValueExpression =
N'(<Element Code="[^"]+")\s+Value=""\s+(ExtraData="[^"]+")\s*/>';
SET @EmptyValueReplacement = N'$1 $2 />';
UPDATE tbl
SET XmlField = SQL#.RegEx_Replace4k(
SQL#.RegEx_Replace4k(
CONVERT(NVARCHAR(4000), tbl.XmlField),
@NonEmptyValueExpression,
@NonEmptyValueReplacement,
-1, 1, ''),
@EmptyValueExpression,
@EmptyValueReplacement,
-1, 1, '')
FROM SchemaName.TableName tbl
WHERE tbl.XmlField.exist('Root/Elements/Element/@Value') = 1;
<Value>
각 요소마다 여러 요소 를 계획하지 않으면 이것에 대한 이점을 생각할 수 없습니다<Element>
. 그렇지 않은 경우 속성을 요소로 옮기면 XML이 부풀어지고 효율성이 떨어집니다.