在SQL2012中粉碎XML数据 - 如何从嵌套元素

时间:2016-09-08 10:08:17

标签: xml tsql sql-server-2012

我有一个名为 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的建议,我尝试了以下但没有运气,我一定错过了什么!

我无法指向显示的实际XML数据,因为这是通过应用程序存储到“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 

1 个答案:

答案 0 :(得分:3)

试试这样:

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-elements ,则需要.nodes()来返回<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

与此一起

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的元素(不是数据类型,元素的名称!)并列出 row-wise ......

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

相关问题