Đối với điều này, bạn muốn sử dụng .exist()
hàm XML vì nó sẽ trả về giá trị BIT (tức là boolean) cho biết liệu XQuery có tìm thấy gì hay không.
Để xử lý vị trí không tĩnh của một phần tử, bạn sẽ sử dụng một trong hai *
(chỉ ra rằng nó sẽ kiểm tra tất cả các nút của một cấp cụ thể, nhưng không phải các cấp khác) hoặc //
(chỉ ra rằng nó nên kiểm tra tất cả các nút ở cấp đó và bên dưới).
Các ví dụ sau sử dụng truy vấn mẫu từ câu hỏi làm cơ sở và thêm một vài trường hợp thử nghiệm để đặt phần tử ở các mức khác nhau và thêm trường hợp thử nghiệm thay đổi tên để cho thấy XQuery không chỉ chọn mọi thứ.
Kiểm tra cài đặt (chạy một lần)
SET NOCOUNT ON;
CREATE TABLE #Table (ID INT NOT NULL, XmlCol XML);
INSERT INTO #Table (ID, XmlCol) VALUES (1, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
<ContactLName>Brandt</ContactLName>
</MCTLocation>
</MCTLocations>
</root>');
INSERT INTO #Table (ID, XmlCol) VALUES (2, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
<ContactLName>Grandt</ContactLName>
</MCTLocation>
</MCTLocations>
</root>');
INSERT INTO #Table (ID, XmlCol) VALUES (3, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
</MCTLocation>
</MCTLocations>
<ContactLName>Brandt</ContactLName>
</root>');
INSERT INTO #Table (ID, XmlCol) VALUES (4, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
</MCTLocation>
<NewElement>
<SubElement>
<ContactLName>Brandt</ContactLName>
</SubElement>
</NewElement>
</MCTLocations>
</root>');
INSERT INTO #Table (ID, XmlCol) VALUES (5, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
</MCTLocation>
<NewerElement>
<ContactLName>Brandt</ContactLName>
</NewerElement>
</MCTLocations>
</root>');
INSERT INTO #Table (ID, XmlCol) VALUES (6, N'
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
<MCTLocation>
<Address>1234 Main Street</Address>
<ContactFName>Chris</ContactFName>
</MCTLocation>
<NewerElement>
</NewerElement>
</MCTLocations>
</root>
<ContactLName>Brandt</ContactLName>
');
Kiểm tra 1 ( *
thay cho tên nút)
Điều này sẽ kiểm tra tất cả các nút ở mức quy định, trong trường hợp này là dưới <root>
. Nhưng nó sẽ không kiểm tra các cấp độ khác.
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'/*/ContactLName[text()="Brandt"]') = 1;
Trả về hàng có ID
giá trị là 3.
Kiểm tra 2 ( *
thay cho tên nút)
Điều này sẽ kiểm tra tất cả các nút ở mức quy định, trong trường hợp này là dưới <root><MCTLocations>
. Nhưng nó sẽ không kiểm tra các cấp độ khác.
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'/root/MCTLocations/*/ContactLName[text()="Brandt"]') = 1;
Trả về các hàng có ID
giá trị 1 và 5.
Kiểm tra 3 ( //
thay cho tên nút)
Điều này sẽ rà soát tất cả các nút bắt đầu ở mức quy định, trong trường hợp này chỉ là dưới <root><MCTLocations>
, và dưới đây .
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'/root/MCTLocations//ContactLName[text()="Brandt"]') = 1;
Trả về các hàng có ID
giá trị 1, 4 và 5.
Kiểm tra 4 ( /*
hoặc */
thay cho tên nút)
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'*//ContactLName[text()="Brandt"]') = 1;
-- and:
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//*/ContactLName[text()="Brandt"]') = 1;
Cả hai hàng trả về có ID
giá trị 1, 3, 4 và 5.
Chúng không trả về ID hàng 6 do *
là trình giữ chỗ cho một nút, do đó mức cao nhất được phép sẽ nằm dưới <root>
(hoặc bất kỳ nút cấp cao nhất nào).
Kiểm tra 5 ( //
ở cấp cao nhất)
Điều này sẽ kiểm tra tất cả các nút bắt đầu ở cấp cao nhất.
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//ContactLName[text()="Brandt"]') = 1;
Trả về các hàng có ID
giá trị 1, 3, 4, 5 và 6.
Kiểm tra 6 (sử dụng giá trị biến cục bộ cho văn bản phần tử trong XQuery)
DECLARE @Name NVARCHAR(50) = N'Brandt';
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//ContactLName[text()=sql:variable("@Name")]') = 1;
SET @Name = N'Grandt';
-- exact same query, just different value in the variable
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//ContactLName[text()=sql:variable("@Name")]') = 1;
Truy vấn đầu tiên trả về các hàng có ID
giá trị 1, 3, 4, 5 và 6.
Truy vấn thứ hai trả về hàng có ID
giá trị là 2.
Kiểm tra 7 (sử dụng hàm và chuỗi ký tự cho tên thành phần trong XQuery)
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//.[local-name()="NewerElement"]') = 1;
Trả về các hàng có ID
giá trị là 5 và 6.
Kiểm tra 8 (sử dụng hàm với giá trị biến cục bộ cho tên thành phần trong XQuery)
DECLARE @Node NVARCHAR(50) = N'SubElement';
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//.[local-name()=sql:variable("@Node")]') = 1;
Trả về hàng có ID
giá trị là 4.
Kiểm tra 9 (đặt tất cả các mảnh lại với nhau)
DECLARE @NodeName NVARCHAR(50) = N'ContactLName',
@NodeText NVARCHAR(500) = N'Brandt';
SELECT *
FROM #Table tmp
WHERE tmp.[XmlCol].exist(N'//.[local-name()=sql:variable("@NodeName")]
[text()=sql:variable("@NodeText")]') = 1;
Trả về các hàng có ID
giá trị 1, 3, 4, 5 và 6.
Lưu ý chung về XML:
Dữ liệu XML (trong SQL Server) được mã hóa dưới dạng UTF-16 Little Endian, giống như NVARCHAR
/ NCHAR
. Do đó, tốt nhất là nên thêm tiền tố vào các chữ có chữ hoa - N
khi giá trị thực sự là XML.