我可以在解析时让 SQL 递增计数 XML 个元素吗?
Can I have SQL incrementally count XML elements while parsing?
所以这是我第一次尝试解析 XML,我正在努力弄清楚如何让它按我想要的方式工作。
给定以下 XML 格式:
<Tiles>
<TileRow>
<TileValue>2</TileValue>
<TileValue>3</TileValue>
<TileValue>4</TileValue>
</TileRow>
<TileRow>
<TileValue>2</TileValue>
<TileValue>7</TileValue>
</TileRow>
</Tiles>
我希望将其放入 SQL table 中,如下所示:
| X | Y | Val |
|---|---|-----|
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 1 | 3 | 4 |
| 2 | 1 | 2 |
| 2 | 2 | 7 |
基本上,想象一个网格,每个“TileRow”在该网格中开始一个新行。每个“TileValue”分配该网格中的列位置,实际 TileValue 是该网格中 'cell' 中的内容。
有没有办法让 SQL 'count' 每次经过一个元素时,或者类似的效果?
请尝试以下解决方案。
它基于 XQuery 中的节点顺序比较运算符。
Node Order Comparison Operators
SQL
DECLARE @xml XML =
N'<Tiles>
<TileRow>
<TileValue>2</TileValue>
<TileValue>3</TileValue>
<TileValue>4</TileValue>
</TileRow>
<TileRow>
<TileValue>2</TileValue>
<TileValue>7</TileValue>
</TileRow>
</Tiles>';
SELECT c.value('for $i in . return count(/Tiles/TileRow[. << $i])', 'INT') AS [X]
, c.value('for $i in . return count(../*[. << $i]) + 1', 'INT') AS [Y]
, c.value('(./text())[1]', 'INT') as Value
FROM @xml.nodes('/Tiles/TileRow/TileValue') AS t(c);
输出
+---+---+-------+
| X | Y | Value |
+---+---+-------+
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 1 | 3 | 4 |
| 2 | 1 | 2 |
| 2 | 2 | 7 |
+---+---+-------+
不幸的是,SQL服务器不支持直接返回position()
,它只允许在谓词中返回。如果是,那么您可以简单地查询:
select
v.TileValue.value('position(parent::*)[1]','int'),
v.TileValue.value('./position()[1]','int'),
v.TileValue.value('text()[1]','int')
from @x.nodes('/Tiles/TileRow/TileValue') v(TileValue)
相反,您可以使用 ROW_NUMBER()
来模拟它
select
v1.rn,
row_number() over (partition by v1.rn order by (select 1)),
v2.TileValue.value('text()[1]','int')
from (
select v1.TileRow.query('.') TileRow,
row_number() over (order by (select 1)) rn
from @x.nodes('/Tiles/TileRow') v1(TileRow)
) v1
cross apply v1.TileRow.nodes('TileRow/TileValue') v2(TileValue)
所以这是我第一次尝试解析 XML,我正在努力弄清楚如何让它按我想要的方式工作。
给定以下 XML 格式:
<Tiles>
<TileRow>
<TileValue>2</TileValue>
<TileValue>3</TileValue>
<TileValue>4</TileValue>
</TileRow>
<TileRow>
<TileValue>2</TileValue>
<TileValue>7</TileValue>
</TileRow>
</Tiles>
我希望将其放入 SQL table 中,如下所示:
| X | Y | Val |
|---|---|-----|
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 1 | 3 | 4 |
| 2 | 1 | 2 |
| 2 | 2 | 7 |
基本上,想象一个网格,每个“TileRow”在该网格中开始一个新行。每个“TileValue”分配该网格中的列位置,实际 TileValue 是该网格中 'cell' 中的内容。
有没有办法让 SQL 'count' 每次经过一个元素时,或者类似的效果?
请尝试以下解决方案。
它基于 XQuery 中的节点顺序比较运算符。
Node Order Comparison Operators
SQL
DECLARE @xml XML =
N'<Tiles>
<TileRow>
<TileValue>2</TileValue>
<TileValue>3</TileValue>
<TileValue>4</TileValue>
</TileRow>
<TileRow>
<TileValue>2</TileValue>
<TileValue>7</TileValue>
</TileRow>
</Tiles>';
SELECT c.value('for $i in . return count(/Tiles/TileRow[. << $i])', 'INT') AS [X]
, c.value('for $i in . return count(../*[. << $i]) + 1', 'INT') AS [Y]
, c.value('(./text())[1]', 'INT') as Value
FROM @xml.nodes('/Tiles/TileRow/TileValue') AS t(c);
输出
+---+---+-------+
| X | Y | Value |
+---+---+-------+
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 1 | 3 | 4 |
| 2 | 1 | 2 |
| 2 | 2 | 7 |
+---+---+-------+
不幸的是,SQL服务器不支持直接返回position()
,它只允许在谓词中返回。如果是,那么您可以简单地查询:
select
v.TileValue.value('position(parent::*)[1]','int'),
v.TileValue.value('./position()[1]','int'),
v.TileValue.value('text()[1]','int')
from @x.nodes('/Tiles/TileRow/TileValue') v(TileValue)
相反,您可以使用 ROW_NUMBER()
select
v1.rn,
row_number() over (partition by v1.rn order by (select 1)),
v2.TileValue.value('text()[1]','int')
from (
select v1.TileRow.query('.') TileRow,
row_number() over (order by (select 1)) rn
from @x.nodes('/Tiles/TileRow') v1(TileRow)
) v1
cross apply v1.TileRow.nodes('TileRow/TileValue') v2(TileValue)