【问题标题】:Shredding XML data in SQL2012- How can I get values from nested elements在 SQL2012 中粉碎 XML 数据-如何从嵌套元素中获取值
【发布时间】:2016-09-08 10:08:16
【问题描述】:

我有一个名为 Audit.Event 的表,它捕获用户事件,该表中的一列将数据存储为 xml,其结构如下

XML 数据

<OrganisationSearchEvent xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Options>
    <IsAgency>false</IsAgency>
    <IsCharity>false</IsCharity>
    <IsCompany>false</IsCompany>
    <IsEducationalEstablishment>false</IsEducationalEstablishment>
    <IsProgrammeProvider>false</IsProgrammeProvider>
    <Name i:nil="true" />
    <OrganisationIDs xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
    <ProfessionalBodies xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
    <Sectors xmlns:d3p1="http://schemas.datacontract.org/2004/07/System">
      <d3p1:int>21</d3p1:int>
      <d3p1:int>82</d3p1:int>
    </Sectors>
    <SubSector xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
  </Options>
  <Paging>
    <EndRecord i:nil="true" />
    <PageNumber>1</PageNumber>
    <PagingMode>Paged</PagingMode>
    <RecordsPerPage>20</RecordsPerPage>
    <StartRecord i:nil="true" />
    <TotalPages>1</TotalPages>
  </Paging>
</OrganisationSearchEvent>

我需要分解 xml 并在名为 d3p1:int 的元素中捕获数据。到目前为止,我已经编写了以下查询:

查询

SELECT 
Data.value('(//d3p1:int)[1]', 'int') AS [SectorID],
FROM [Audit].[EventData]
Cross Apply Data.nodes('//OrganisationSearchEvent/Options/Sectors') as Test(X)
Where EventTypeID = 7 
Order By CapturedDateTime Desc

我希望看到的只是

+----------+
| SectorID |
+----------+
|       10 |
|       45 |
|       50 |
|       22 |
|        6 |
+----------+

但是我得到了以下错误

名称“d3p1”不表示命名空间。

如果我只用“d3p1”替换“d3p1:int”,则会返回空值

如果我在 select 子句中使用以下行作为测试,则返回该元素的正确数据。

Data.value('(//Name)[1]','nvarchar(100)') AS [Name]

谁能给我指出正确的方向,我不确定这是什么原因

谢谢

--编辑--

按照 Shnugo 的建议,我尝试了以下方法,但没有成功,我一定错过了一些东西!

我无法指向实际的 XMLdata,因为它正在通过应用程序存储到“Autit.EventData”表中的列中,我试图做的是这个。

尝试 1

Declare @xml XML=[Audit].[EventData].[Data]

;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS d3p1)
SELECT i.value('.','int') AS [SectorID]
FROM @xml.nodes('/OrganisationSearchEvent/Options/Sectors/d3p1:int') as A(i)

但我得到了错误

无法绑定多部分标识符“Audit.EventData.Data”。

我认为我仍然需要使用该表,所以我接下来尝试了这个

尝试 2

;WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema-instance' AS d3p1)
SELECT i.value('.','int') AS [SectorID]
FROM [Audit].[EventData]

Cross Apply Data.nodes('/OrganisationSearchEvent/Options/Sectors/d3p1:int') as A(i)

但这没有任何回报

最终解决方案

这是我用来返回正确数据的最终查询

 SELECT 
T.C.value('.', 'int') as [SelectedID's] 
from Audit.[EventData] 
cross apply Data.nodes('/OrganisationSearchEvent/Options/Sectors/*') as T(C) 
where EventTypeID = 7 
order by CapturedDateTime desc 

【问题讨论】:

    标签: xml tsql sql-server-2012


    【解决方案1】:

    试试这样:

    DECLARE @xml XML=
    '<OrganisationSearchEvent xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Options>
        <IsAgency>false</IsAgency>
        <IsCharity>false</IsCharity>
        <IsCompany>false</IsCompany>
        <IsEducationalEstablishment>false</IsEducationalEstablishment>
        <IsProgrammeProvider>false</IsProgrammeProvider>
        <Name i:nil="true" />
        <OrganisationIDs xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
        <ProfessionalBodies xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
        <Sectors xmlns:d3p1="http://schemas.datacontract.org/2004/07/System">
          <d3p1:int>21</d3p1:int>
          <d3p1:int>82</d3p1:int>
        </Sectors>
        <SubSector xmlns:d3p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
      </Options>
      <Paging>
        <EndRecord i:nil="true" />
        <PageNumber>1</PageNumber>
        <PagingMode>Paged</PagingMode>
        <RecordsPerPage>20</RecordsPerPage>
        <StartRecord i:nil="true" />
        <TotalPages>1</TotalPages>
      </Paging>
    </OrganisationSearchEvent>';
    
    WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/System' AS d3p1)
    SELECT i.value('.','int')
    FROM @xml.nodes('//d3p1:int') AS A(i);
    

    如果没有命名空间,您可能会使用像这里这样的通配符

    SELECT i.value('.','int')
    FROM @xml.nodes('//*:int') AS A(i);
    

    甚至是完整路径

    WITH XMLNAMESPACES('http://schemas.datacontract.org/2004/07/System' AS d3p1)
    SELECT i.value('.','int')
    FROM @xml.nodes('/OrganisationSearchEvent/Options/Sectors/d3p1:int') AS A(i);
    

    这取决于您的要求。一般建议是:尽可能具体。

    关于您的代码:由于您想阅读所有 int 元素,您需要 .nodes() 来返回您的 &lt;d3p1:int&gt; 元素。您的查询停止了一级到高。其次,如果您必须处理命名空间,则必须明确使用它们或使用通配符。

    更新

    如果不知道您的实际数据库,很难指出您...

    根据你的问题,我认为:

    SELECT 
    Data.value('(//d3p1:int)[1]', 'int') AS [SectorID],
    FROM [Audit].[EventData]
    Cross Apply Data.nodes('//OrganisationSearchEvent/Options/Sectors') as Test(X)
    Where EventTypeID = 7 
    Order By CapturedDateTime Desc
    

    连同这个

    Data.value('(//Name)[1]','nvarchar(100)') AS [Name]
    

    返回正确的数据?

    如果是这样,最不具体的方法可能是这样的:

    SELECT 
    Data.value('.','int') AS SectorID
    FROM [Audit].[EventData]
    Cross Apply Data.nodes('//*:int') as Test(X)
    Where EventTypeID = 7 
    Order By CapturedDateTime Desc
    

    这应该选择任何名为int 的元素(不是数据类型,而是元素的名称!)并列出这个逐行...

    如果你让它工作,你可能会尝试找到一个更具体的XPath,但这应该 - 至少 - 返回正确的值......

    【讨论】:

    • 感谢您的建议,我会试试这些
    • 感谢您的帮助,这帮助我找到了答案
    猜你喜欢
    • 1970-01-01
    • 2021-10-21
    • 2018-04-12
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 2012-05-23
    相关资源
    最近更新 更多