Xem liệu phần tử XML có tồn tại ở bất kỳ cấp nào trong tài liệu với một giá trị cụ thể không


7

Có thể truy vấn XML để tìm xem một phần tử cụ thể có giá trị nhất định không? Ví dụ: nếu tôi muốn xem liệu XML bên dưới có giá trị "Brandt" không <ContactFName>.

Nhưng lưu ý, vị trí của phần tử có thể thay đổi. Trong một số trường hợp, nó có thể ở trong /root/MCTLocations/MCTLocationhoặc có thể nhảy xuống dưới gốc hoặc xuất hiện ở một nơi khác ...

Và, có thể tham số hóa tên thành phần?

DECLARE @table TABLE (XmlCol XML)

INSERT INTO @table (XmlCol) VALUES ('
<root>
<MCTClientName>John</MCTClientName>
<MCTClientCity>Palm Beach</MCTClientCity>
<MCTLocations>
    <MCTLocation>
        <Address>1234 Main Street</Address>
        <ContactFName>Chris</ContactFName>
        <ContactLName>Brandt</ContactLName>
    </MCTLocation>
</MCTLocations>
</root>')

SELECT * FROM @table WHERE ??

Câu trả lời:


13

Đố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ó IDgiá 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ó IDgiá 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ó IDgiá 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ó IDgiá 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ó IDgiá 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ó IDgiá trị 1, 3, 4, 5 và 6.

Truy vấn thứ hai trả về hàng có IDgiá 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ó IDgiá 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ó IDgiá 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ó IDgiá 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 - Nkhi giá trị thực sự là XML.


1
Đây là công cụ tuyệt vời! Cảm ơn bạn!! Một câu hỏi cuối cùng - có thể tham số hóa tên phần tử không?
John Hennesey

3
Đây là bộ ví dụ tốt nhất tôi có trong một phản hồi. Cảm ơn bạn rất nhiều!
John Hennesey

2
@JohnHennesey Bạn khá hoan nghênh. Và cảm ơn bạn vì lời khen đó :-).
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.