CẬP NHẬT:
Tôi đã cập nhật mã, cũng như XML đầu vào và đầu ra trong truy vấn mẫu bên dưới để phản ánh yêu cầu mới nhất, được nêu trong một nhận xét về câu trả lời tốt của @ Mikael , đó là:
không tạo phần tử Giá trị nếu @Value trống hoặc không tồn tại
Mặc dù một biểu thức có thể khớp chính xác với biến thể mới này, nhưng dường như không có cách nào để bỏ qua <Value/>
phần tử trống trong một lần truyền vì logic điều kiện không được phép trong chuỗi thay thế. Vì vậy, tôi đã điều chỉnh điều này thành một sửa đổi 2 phần: một vượt qua để có được các @Value
thuộc tính không trống và một vượt qua để có được các @Value
thuộc tính trống . Không cần xử lý <Element>
s thiếu @Value
thuộc tính vì mong muốn là không có <Value>
phần tử nào.
Một tùy chọn là coi XML như một chuỗi thông thường và biến đổi nó dựa trên một mẫu. Điều này có thể dễ dàng thực hiện bằng cách sử dụng Biểu thức chính quy (cụ thể là chức năng "Thay thế") có thể được cung cấp qua mã SQLCLR.
Ví dụ dưới đây sử dụng UDF vô hướng RegEx_Replace từ thư viện SQL # (mà tôi là tác giả, nhưng hàm RegEx này có sẵn trong phiên bản Miễn phí, cùng với nhiều phiên bản khác):
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
Các PRINT
báo cáo nằm trong đó chỉ để làm cho việc so sánh song song dễ dàng hơn trong tab "Tin nhắn". Kết quả đầu ra là (Tôi đã sửa đổi XML gốc một chút để làm rõ rằng chỉ có các phần mong muốn được chạm vào và không có gì khác):
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>
Nếu bạn muốn cập nhật một trường trong bảng, bạn có thể điều chỉnh các mục trên thành như sau:
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>
yếu tố cho mỗi yếu tố<Element>
. Nếu không, thì việc di chuyển thuộc tính sang một phần tử chỉ làm cho XML trở nên cồng kềnh hơn và có thể kém hiệu quả hơn.