【问题标题】:How to search the XML node values stored in table column in SQL Server如何在 SQL Server 中搜索存储在表列中的 XML 节点值
【发布时间】:2020-07-15 16:59:19
【问题描述】:

我指的是这个:How to query values from xml nodes? 并试图找到搜索节点值(如果存在)的最佳和快速方法,但不知何故,它看起来比我最初想的更完整。

数据库表中有大约 10K 条记录。其中一列将 XML 存储在表中,列值与此类似(还有很多其他节点):

<GrobReportXmlFileXmlFile>
   <GrobReport>
       <ReportHeader>
          <OrganizationReportReferenceIdentifier>Hello</OrganizationReportReferenceIdentifier>
          <OrganizationNumber>Hi</OrganizationNumber>
       </ReportHeader>
  </GrobReport>
   <GrobReport>
       <ReportHeader>
          <OrganizationReportReferenceIdentifier>Find</OrganizationReportReferenceIdentifier>
          <OrganizationNumber>Me</OrganizationNumber>
       </ReportHeader>
  </GrobReport>

我试过的脚本是:

 select columnname.value('(GrobReportXmlFileXmlFile/GrobReport/ReportHeader/OrganizationReportReferenceIdentifier/)[Hello]',nvarchar(max)) from Table

注意:我的列名是:

列名(nvarchar(max),null)

但是,它的显示错误,nvarchar 无法被内置函数识别。

我已经像这样更改了我的查询:

 select T.[columnname].value('(GrobReportXmlFileXmlFile/GrobReport/ReportHeader/OrganizationReportReferenceIdentifier/)[Hello]','nvarchar(max)') from Table as T

但是,在这种情况下,我收到以下错误:

不能在 nvarchar(max) 上调用方法

任何想法,如果 .value 需要被其他函数替换,因为它的类型是 nvarchar(max)?我可以尝试“价值”功能的替代品吗?

我想查找任何列/节点中是否存在任何特定值(比如说“Hello”)?如果存在,那么它应该返回我搜索值所在的记录数(行数)在场吗?

谢谢

【问题讨论】:

  • “nvarchar(max)”应该是什么?什么是“最大值”?看起来语法不正确
  • 对不起,我没听懂你的问题。列数据类型是这样定义的。数据库是 Azure SQL DB,我正在使用 SSMS 2019 编写/执行查询。
  • nvarchar(MAX) 是否应该用单引号括起来:'nvarchar(max)'?
  • 对不起,我的错。是的,我改变了这一点。但是,现在我收到一个新错误:找不到列“columnname”或用户定义的函数或聚合“columnname.value”,或者名称不明确。
  • columnname 应该是表上物理列的名称:select [name_of_col_here].value

标签: xml tsql azure-sql-database xquery


【解决方案1】:

您可以尝试以下三种方法:

  1. 带有WHERE 子句的CTE 和矩形/关系数据集。
  2. XPath 谓词。
  3. .exist() 方法。

方法#1。 .nodes().value() 方法的组合将 XML 转换为 CTE 内的矩形数据集。之后,WHERE 子句根据搜索条件查找所需内容。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata NVARCHAR(MAX));
INSERT INTO @tbl (xmldata)
VALUES
(N'<GrobReportXmlFileXmlFile>
    <GrobReport>
        <ReportHeader>
            <OrganizationReportReferenceIdentifier>Hello</OrganizationReportReferenceIdentifier>
            <OrganizationNumber>Hi</OrganizationNumber>
        </ReportHeader>
    </GrobReport>
    <GrobReport>
        <ReportHeader>
            <OrganizationReportReferenceIdentifier>Find</OrganizationReportReferenceIdentifier>
            <OrganizationNumber>Me</OrganizationNumber>
        </ReportHeader>
    </GrobReport>
</GrobReportXmlFileXmlFile>');
-- DDL and sample data population, end

DECLARE @searchParam VARCHAR(20) = 'Hello';

-- Method #1
;WITH cte AS
(
    SELECT ID, TRY_CAST(xmldata AS XML) AS xmldata
    FROM @tbl
), rs AS
(
SELECT ID 
    , c.value('(OrganizationReportReferenceIdentifier/text())[1]','VARCHAR(20)') AS OrganizationReportReferenceIdentifier
    , c.value('(OrganizationNumber/text())[1]','VARCHAR(20)') AS OrganizationNumber
FROM cte AS tbl
    CROSS APPLY tbl.xmldata.nodes('/GrobReportXmlFileXmlFile/GrobReport/ReportHeader') AS t(c)
)
SELECT * FROM  rs
-- apply any filter(s) here
WHERE OrganizationReportReferenceIdentifier = @searchParam;

输出

+----+---------------------------------------+--------------------+
| ID | OrganizationReportReferenceIdentifier | OrganizationNumber |
+----+---------------------------------------+--------------------+
|  1 | Hello                                 | Hi                 |
|  1 | Find                                  | Me                 |
+----+---------------------------------------+--------------------+

方法 #2,基于 XPath 谓词

-- Method #2
;WITH cte AS
(
    SELECT ID, TRY_CAST(xmldata AS XML) AS xmldata
    FROM @tbl
)
SELECT ID 
    , c.value('(OrganizationReportReferenceIdentifier/text())[1]','VARCHAR(20)') AS OrganizationReportReferenceIdentifier
    , c.value('(OrganizationNumber/text())[1]','VARCHAR(20)') AS OrganizationNumber
FROM cte AS tbl
    CROSS APPLY tbl.xmldata.nodes('/GrobReportXmlFileXmlFile/GrobReport/ReportHeader[(OrganizationReportReferenceIdentifier/text())[1] eq sql:variable("@searchParam")]') AS t(c);

输出

+----+---------------------------------------+--------------------+
| ID | OrganizationReportReferenceIdentifier | OrganizationNumber |
+----+---------------------------------------+--------------------+
|  1 | Hello                                 | Hi                 |
+----+---------------------------------------+--------------------+

方法 #3,基于 .exist() 方法。

-- Method #3
;WITH cte AS
(
    SELECT ID, TRY_CAST(xmldata AS XML) AS xmldata
    FROM @tbl
)
SELECT ID 
    , c.value('(OrganizationReportReferenceIdentifier/text())[1]','VARCHAR(20)') AS OrganizationReportReferenceIdentifier
    , c.value('(OrganizationNumber/text())[1]','VARCHAR(20)') AS OrganizationNumber
FROM cte AS tbl
    CROSS APPLY tbl.xmldata.nodes('/GrobReportXmlFileXmlFile/GrobReport/ReportHeader') AS t(c)
WHERE c.exist('OrganizationReportReferenceIdentifier[. eq sql:variable("@searchParam")]') = 1;

【讨论】:

  • 好答案,加分:-)
  • 谢谢。但是,我的列类型不是 XML,我无法更改它。我收到错误:只能在 XML 类型的列上调用 XMLDT 方法“节点”。请问还有其他解决方案吗?
  • @AskMe,这就是为什么在提问时提供 DDL 和样本数据群如此重要的原因。我将列数据类型从XML 修改为NVARCHAR(MAX) 并更新了答案。
猜你喜欢
  • 2012-04-22
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多