我可以在解析时让 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)