代码之家  ›  专栏  ›  技术社区  ›  Paulo Santos

如何用T-SQL XQuery转换XML表?

  •  0
  • Paulo Santos  · 技术社区  · 15 年前

    假设我们有以下XML:

    <root>
      <row>
        <column>row 1 col 1</column>
        <column>row 1 col 2</column>
        <column>row 1 col 3</column>
      </row>
      <row>
        <column>row 2 col 1</column>
        <column>row 2 col 2</column>
        <column>row 2 col 3</column>
      </row>
      <row>
        <column>row 3 col 1</column>
        <column>row 3 col 2</column>
        <column>row 3 col 3</column>
      </row>
    </root>
    

    我该如何使用 T-SQL XQuery 到:

    <root>
        <column>
            <row>row 1 col 1</row>
            <row>row 2 col 1</row>
            <row>row 3 col 1</row>
        </column>
        <column>
            <row>row 1 col 2</row>
            <row>row 2 col 2</row>
            <row>row 3 col 2</row>
        </column>
        <column>
            <row>row 1 col 3</row>
            <row>row 2 col 3</row>
            <row>row 3 col 3</row>
        </column>
    </root>
    
    2 回复  |  直到 13 年前
        1
  •  1
  •   AakashM    15 年前

    我怀疑使用 PIVOT 但我不太清楚,不能肯定地说。我在这里提供的是有效的。为了更好地格式化和提供评论,我已经将它分成若干块:

    首先,让我们捕获示例数据

    -- Sample data
    DECLARE @x3 xml
    
    SET @x3 = '
    <root>
      <row>
        <column>row 1 col 1</column>
        <column>row 1 col 2</column>
        <column>row 1 col 3</column>
      </row>
      <row>
        <column>row 2 col 1</column>
        <column>row 2 col 2</column>
        <column>row 2 col 3</column>
      </row>
      <row>
        <column>row 3 col 1</column>
        <column>row 3 col 2</column>
        <column>row 3 col 3</column>
      </row>
    </root>
    '
    
    DECLARE @x xml
    SET @x = @x3
    
    -- @x is now our input
    

    现在实际的转置代码是:

    确定矩阵的大小:

    WITH Size(Size) AS
    (
        SELECT CAST(SQRT(COUNT(*)) AS int) 
        FROM @x.nodes('/root/row/column') T(C)
    )
    

    切碎数据,使用 ROW_NUMBER 捕获索引 -1 使其从零开始),并使用索引上的模和整数除来计算 新的 行和列编号:

    ,Flattened(NewRow, NewCol, Value) AS
    (
        SELECT
            -- i/@size as old_r, i % @size as old_c, 
            i % (SELECT TOP 1 Size FROM Size) AS NewRow, 
            i / (SELECT TOP 1 Size FROM Size) AS NewCol, 
            Value
        FROM (
            SELECT
                (ROW_NUMBER() OVER (ORDER BY C)) - 1 AS i, 
                C.value('.', 'nvarchar(100)') AS Value
            FROM @x.nodes('/root/row/column') T(C)
            ) ShreddedInput
    )
    

    用这个CTE FlattenedInput 现在我们要做的就是 FOR XML 选项和查询结构正确,我们完成了:

    SELECT
        (
            SELECT Value 'column'
            FROM
                Flattened t_inner
            WHERE
                t_inner.NewRow = t_outer.NewRow
            FOR XML PATH(''), TYPE
        ) row
    FROM
        Flattened t_outer
    GROUP BY NewRow
    FOR XML PATH(''), ROOT('root')
    

    样品输出:

    <root>
      <row>
        <column>row 1 col 1</column>
        <column>row 2 col 1</column>
        <column>row 3 col 1</column>
      </row>
      <row>
        <column>row 1 col 2</column>
        <column>row 2 col 2</column>
        <column>row 3 col 2</column>
      </row>
      <row>
        <column>row 1 col 3</column>
        <column>row 2 col 3</column>
        <column>row 3 col 3</column>
      </row>
    </root>
    

    处理任何尺寸的“正方形”数据。注意缺乏健全性检查/错误处理。

        2
  •  0
  •   animuson    13 年前
    SET @x3 = ' 
    <root> 
      <row> 
        <column>row 1 col 1</column> 
        <column>row 1 col 2</column> 
        <column>row 1 col 3</column> 
      </row> 
      <row> 
        <column>row 2 col 1</column> 
        <column>row 2 col 2</column> 
        <column>row 2 col 3</column> 
      </row> 
      <row> 
        <column>row 3 col 1</column> 
        <column>row 3 col 2</column> 
        <column>row 3 col 3</column> 
      </row> 
    </root> 
    ' 
    
    select @x3 = replace(@x3,'<row>','<rowtemp>')
    select @x3 = replace(@x3,'<column>','<row>')
    select @x3 = replace(@x3,'<rowtemp>','<column>')
    
    select @x3