可以在列中提取存储在XML中的* distinct *键(跨所有行)吗?

时间:2018-05-11 18:04:38

标签: sql-server xml

我有一个包含列的表[users]:

[id] int  
[userdetails] nvarchar(max)

[userdetails]包含以下数据:

<Attributes>
  <Map>
    <entry key="displayName" value="Administrator"/>
    <entry key="email" value="joe.blow@google.com"/>
    <entry key="firstname" value="Joe"/>
    <entry key="lastname" value="tdehdgthrth"/>
    <entry key="another1" value="rthrth"/>
    <entry key="another7" value="etdsryhntdhetdyh"/>
    <entry key="anotherWhatever" value="6546544"/>
  </Map>
</Attributes>

每行可以包含键/值元素计数的不同组合。

在查询中,我想提取所有不同(跨所有行)KEY值的列表。这甚至可能吗?

我之前曾问过类似的问题:

https://stackoverflow.com/a/50281264/8678

从上面查询特定元素的语法如下:

declare @tbl table(id int, userdetails nvarchar(max))
insert @tbl(id,userdetails)
values(1,'<Attributes>
  <Map>
    <entry key="displayName" value="Administrator"/>
    <entry key="email" value="joe.blow@google.com"/>
    <entry key="firstname" value="Joe"/>
    <entry key="lastname" value="Blow"/>
  </Map>
</Attributes>')

;with tbl as (
select id,cast(userdetails as xml) ud
from @tbl)
select id,
t.v.value('entry[@key="displayName"][1]/@value','nvarchar(100)') displayName,
t.v.value('entry[@key="email"][1]/@value','nvarchar(100)') email,
t.v.value('entry[@key="firstname"][1]/@value','nvarchar(100)') firstname,
t.v.value('entry[@key="lastname"][1]/@value','nvarchar(100)') lastname
from tbl 
cross apply ud.nodes('Attributes/Map') t(v)

这个问题的一个明显问题是,它需要知道可用的值并在SQL中对它们进行硬编码,而我在这里要做的是发现可能的键值的不同集合

1 个答案:

答案 0 :(得分:2)

  

在查询中,我想提取所有不同(跨所有行)KEY值的列表。这甚至可能吗?

  

我在这里要做的是发现不同的可能键值是什么。

这将生成所有行中不同键的列表(注意:我不确定每个键值可能有多长,但这只会抓取100个字符;必要时更改):

;WITH tbl AS (
    SELECT id, cast(userdetails as xml) ud
    FROM testSo)
SELECT DISTINCT
    t.v.value('(@key)[1]','nvarchar(100)') anEntryKey
FROM tbl 
CROSS APPLY ud.nodes('//entry') t(v)

如果您需要获取有关每个来自哪个地方的更多信息(哪个ID),您可以获得这样的(非不同的)列表:

;WITH tbl AS (
    SELECT id, cast(userdetails as xml) ud
    FROM testSo)
SELECT
    id,
    t.v.value('(@key)[1]','nvarchar(100)') anEntryKey
FROM tbl 
CROSS APPLY ud.nodes('//entry') t(v)

我使用SQL Server 2017在SQL Fiddle here上测试了这些。