查看 XML 元素是否存在於文件中具有特定值的任何級別
是否可以查詢 XML 以查找特定元素是否具有特定值?例如,如果我想查看下面的 XML 是否在
<ContactFName>
.但請注意,元素的位置可能會發生變化。在某些情況下,它可能在 中
/root/MCTLocations/MCTLocation
,或者它可能跳到根目錄下,或者出現在其他地方……而且,是否可以參數化元素名稱?
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 ??
為此,您需要使用
.exist()
XML 函式,因為它將返回一個 BIT(即布爾值)值,指示 XQuery 是否找到任何內容。要處理元素的非靜態位置,您可以使用
*
(表示它應該檢查特定級別的所有節點,但不檢查其他級別)或//
(表示它應該檢查該級別及以下的所有節點)。以下範例使用來自問題的範例查詢作為基礎,並添加一些測試案例以將元素放置在不同的級別,並添加一個更改名稱的測試案例以表明 XQuery 不只是選擇所有內容。
測試設置(執行一次)
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> ');
測試 1(
*
代替節點名稱)這將檢查指定級別的所有節點,在本例中,它位於
<root>
. 但它不會檢查其他級別。SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'/*/ContactLName[text()="Brandt"]') = 1;
返回
ID
值為 3 的行。測試 2(
*
代替節點名稱)這將檢查指定級別的所有節點,在本例中,它位於
<root><MCTLocations>
. 但它不會檢查其他級別。SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'/root/MCTLocations/*/ContactLName[text()="Brandt"]') = 1;
返回
ID
值為 1 和 5 的行。測試 3(
//
代替節點名稱)這將檢查從指定級別開始的所有節點,在這種情況下
<root><MCTLocations>
,它正好在和 之下。SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'/root/MCTLocations//ContactLName[text()="Brandt"]') = 1;
返回
ID
值為 1、4 和 5 的行。測試 4(
/*
或*/
代替節點名稱)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;
兩者都返回
ID
值為 1、3、4 和 5 的行。
*
由於是單個節點的佔位符,它們不會返回 6 的行 ID ,因此允許的最高級別將位於<root>
(或任何頂級節點)之下。測試 5(
//
在頂層)這將檢查從頂層開始的所有節點。
SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'//ContactLName[text()="Brandt"]') = 1;
返回
ID
值為 1、3、4、5 和 6 的行。測試 6(對 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;
第一個查詢返回
ID
值為 1、3、4、5 和 6 的行。第二個查詢返回
ID
值為 2 的行。測試 7(在 XQuery 中使用函式和字元串文字作為元素名稱)
SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'//.[local-name()="NewerElement"]') = 1;
返回
ID
值為 5 和 6 的行。測試 8(在 XQuery 中使用具有局部變數值的函式作為元素名稱)
DECLARE @Node NVARCHAR(50) = N'SubElement'; SELECT * FROM #Table tmp WHERE tmp.[XmlCol].exist(N'//.[local-name()=sql:variable("@Node")]') = 1;
返回
ID
值為 4 的行。測試 9(將所有部分放在一起)
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;
返回
ID
值為 1、3、4、5 和 6 的行。通用 XML 註釋:
XML 數據(在 SQL Server 中)被編碼為 UTF-16 Little Endian,與
NVARCHAR
/相同NCHAR
。N
因此,當值實際上是 XML 時,最好在字元串文字前加上大寫 - 。