【问题标题】:How to filter an XML field on multiple conditions如何在多个条件下过滤 XML 字段
【发布时间】:2026-01-01 03:30:01
【问题描述】:

我有一张这样的桌子:

CREATE TABLE MyTable(
    Id [int] IDENTITY(1,1) NOT NULL,
    XmlField xml NULL,
    /// Some other fields
)

XML 字段包含 C# Dictionary<int, string> 的 XML 表示。例如:

<dictionary>
    <item>
        <key><int>1</int></key>
        <value><string>Web</string></value>
    </item>
    <item>
        <key><int>2</int></key>
        <value><string>Email</string></value>
    </item>
    // more item
</dictionary>

我想要做的是选择 XmlField 包含(key = 1 with value = 'Web')并且还包含(key = 2 with value ='Email')的所有行。

到目前为止,我只设法过滤了 1 个唯一键/值匹配的行:

SELECT TableId, XmlField FROM MyTable
CROSS APPLY XmlField.nodes('/dictionary/item') x(fields)
WHERE (x.fields.value('(key/int/text())[1]', 'int') = 1 
AND x.fields.value('(value/string/text())[1]', 'varchar(MAX)') = 'Web')

如果我添加AND (x.fields.value('(key/int/text())[1]', 'int') = 2 AND x.fields.value('(value/string/text())[1]', 'varchar(MAX)') = 'Email'),则不会返回任何内容(非常合乎逻辑)。

我也试过不使用CROSS APPLY,而是做一个简单的过滤器:

SELECT TableId, XmlField FROM MyTable
WHERE XmlField.exist('/dictionary/item/key/int[text() = 1]') = 1
AND XmlField.exist('/dictionary/item/value/string[text() = "Web"]') = 1

但它的行为类似于OR,并会返回 xml 包含 2 个键值对的行,例如 (1, Email) 和 (2, Web)

【问题讨论】:

    标签: sql sql-server xml sql-server-2012 cross-apply


    【解决方案1】:

    应该这样做。

    select *
    from MyTable as T
    where T.XmlField.exist('/dictionary[item[key/int/text() = 1 and value/string/text() = "Web"] and   
                                        item[key/int/text() = 2 and value/string/text() = "Email"]]') = 1
    

    【讨论】:

    • 简直完美。看来我需要 XPath 速成课程!非常感谢