鉴于以下XML示例和将{xml分解为关系的select
语句,我需要的是select
的第二列作为类别的序数< / strong>(例如,1表示方向,2表示颜色)。
注意:select中的文字值'rank()'留有占位符。我正在使用rank
,但没有成功。
declare @x xml
set @x = '
<root>
<category>
<item value="north"/>
<item value="south"/>
<item value="east"/>
<item value="west"/>
</category>
<category>
<item value="red"/>
<item value="green"/>
<item value="blue"/>
</category>
</root>'
select c.value('./@value', 'varchar(10)') as "ItemValue",
'rank()' as "CategoryNumber"
from @x.nodes('//item') as t(c)
答案 0 :(得分:2)
Jacob Sebastian在他的博客文章中也有一个有趣的解决方案:
XQuery Lab 23 - Retrieving values and position of elements
根据Jacob的建议,我可以将您的查询重写为:
SELECT
x.value('@value','VARCHAR(10)') AS 'ItemValue',
p.number as 'CategoryNumber'
FROM
master..spt_values p
CROSS APPLY
@x.nodes('/root/category[position()=sql:column("number")]/item') n(x)
WHERE
p.type = 'p'
我得到了所需的输出:
ItemValue CategoryNumber
--------- --------------
north 1
south 1
east 1
west 1
red 2
green 2
blue 2
不幸的是,position()
或fn:id()
函数等更明显的解决方案似乎a)在SQL Server中工作或b)在SQL Server中完全支持: - (
希望这有帮助
马克
答案 1 :(得分:1)
也许是这样的:你得到每个类别的第一个元素并将其用作id。
此:
select c.value('./@value', 'varchar(10)') as "ItemValue",
c.value('../item[1]/@value', 'varchar(10)') as "CategoryNumber"
from @x.nodes('//item') as t(c)
返回:
Item Value | CategoryNumber
---------------------------
north | north
south | north
east | north
west | north
red | red
green | red
blue | red
然后只是
select c.value('./@value', 'varchar(10)') as "ItemValue",
RANK() OVER (ORDER BY c.value('../item[1]/@value', 'varchar(10)')) as "CategoryNumber"
from @x.nodes('//item') as t(c)
然而它返回:
Item Value | CategoryNumber
---------------------------
north | 1
south | 1
east | 1
west | 1
red | 5
green | 5
blue | 5
但它仍然领先一步。
答案 2 :(得分:1)
您不能使用position()
生成输出(为什么??),但您可以将其用作XPath过滤器:
with numbers (n) as (
select 1
union all select 2
union all select 3
union all select 4
union all select 5)
select i.x.value('@value', 'varchar(10)') as [ItemValue],
n.n as [rank]
from numbers n
cross apply @x.nodes('/root/category[position()=sql:column("n.n")]') as c(x)
cross apply c.x.nodes('item') as i(x);
您可以使用实数表来获得更高的排名。对于单个文档中的大量类别来说效率不高,但对于中等数量(数十,数百),可以正常工作。
答案 3 :(得分:0)
与Lukasz的答案类似,我能够通过以下方式获得理想的结果:
SELECT
I.Item_Instance.value('@value','VARCHAR(10)') AS Item_Value,
DENSE_RANK() OVER (ORDER BY C.Category_Instance) AS Category_Ordinal
FROM @x.nodes('/root') AS R(Root_Instance)
CROSS APPLY R.Root_Instance.nodes('category') AS C(Category_Instance)
CROSS APPLY C.Category_Instance.nodes('item') AS I(Item_Instance);
它返回:
Item_Value Category_Ordinal
---------- --------------------
north 1
south 1
east 1
west 1
red 2
green 2
blue 2