【问题标题】:Split columns values and move to rows拆分列值并移动到行
【发布时间】:2019-03-01 07:22:59
【问题描述】:

我想将该数据拆分并移动到行中。我有很多列需​​要拆分并移动到行。单列数据是可能的,但我没有得到多列的解决方案。ms sql 或 Excel 中的解决方案都是可以接受的。请找到屏幕截图。

提前致谢

【问题讨论】:

  • 这在任何 SQL 数据库中都是一件痛苦的事情。如果您可以在 SQL Server 之外处理此问题,那么我建议您这样做。
  • 虽然,总的来说,我同意蒂姆的观点,但仍然添加了一些直接的方法来获得预期的解析结果

标签: sql sql-server excel database


【解决方案1】:

很遗憾,SPLIT_STRING() 没有“序数”或“索引”选项。因此,您无法真正按已知顺序检索值。 (实际上,它确实会按顺序返回值,但不能保证。)

而且,SQL 表和结果集是无序的。因此,即使代码似乎可以工作,依赖排序也是一种非常糟糕的做法。

我建议使用递归 CTE:

with t as (
      select 'prod1' as name, '3,5,6,9' as col1, '33,44,66,7' as col2, '66,7' as col3
     ),
     cte as (
      select name, 1 as lev,
             convert(varchar(max), left(col1, charindex(',', col1 + ',') - 1)) as col1,
             convert(varchar(max), stuff(col1, 1, charindex(',', col1 + ','), '')) as col1_rest,
             convert(varchar(max), left(col2, charindex(',', col2 + ',') - 1)) as col2,
             convert(varchar(max), stuff(col2, 1, charindex(',', col2 + ','), '')) as col2_rest,
             convert(varchar(max), left(col3, charindex(',', col3 + ',') - 1)) as col3,
             convert(varchar(max), stuff(col3, 1, charindex(',', col3 + ','), '')) as col3_rest
      from t
      union all
      select name, lev + 1,
             left(col1_rest, charindex(',', col1_rest + ',') - 1) as col1,
             stuff(col1_rest, 1, charindex(',', col1_rest + ','), '') as col1_rest,
             left(col2_rest, charindex(',', col2_rest + ',') - 1) as col2,
             stuff(col2_rest, 1, charindex(',', col2_rest + ','), '') as col2_rest,
             left(col3_rest, charindex(',', col3_rest + ',') - 1) as col3,
             stuff(col3_rest, 1, charindex(',', col3_rest + ','), '') as col3_rest
      from cte
      where col1_rest <> '' or col2_rest <> '' or col3_rest <> ''
     )
select name, col1, col2, col3
from cte;

Here 是一个 dbfiddle。

【讨论】:

    【解决方案2】:

    一些免责声明:

    • STRING_SPLIT 需要 SQL Server 2016+
    • MAXDOP 1 特意添加

    SQL:

    -- seeding data
    DECLARE @data TABLE ([Name] VARCHAR(50), Column1  VARCHAR(50), Column2  VARCHAR(50), Column3  VARCHAR(50))
    INSERT @data VALUES ('Prod1', '3,5,6,9', '33,44,66,7', '66,7')
    
    -- splitting strings into coluns
    ;WITH cte_col1 AS (
    SELECT Name,
           Col1.value AS ColumnValue,
           ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn,
           1 AS ColumnID       
    FROM @data d
        CROSS APPLY STRING_SPLIT(d.Column1, ',') AS Col1
    )
    , cte_col2 AS (
    SELECT Name,
           Col2.value AS ColumnValue,
           ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn,
           2 AS ColumnID
    FROM @data d
        CROSS APPLY STRING_SPLIT(d.Column2, ',') AS Col2
    )
    , cte_col3 AS (
    SELECT Name,
           Col3.value AS ColumnValue,
           ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn,
           3 AS ColumnID
    FROM @data d
        CROSS APPLY STRING_SPLIT(d.Column3, ',') AS Col3
    )
    
    -- gluing all parts together
    SELECT 
        d.Name
    ,   min (CASE WHEN d.ColumnID = 1 THEN d.ColumnValue END ) AS Column1
    ,   min (CASE WHEN d.ColumnID = 2 THEN d.ColumnValue END ) AS Column2
    ,   min (CASE WHEN d.ColumnID = 3 THEN d.ColumnValue END ) AS Column3
    FROM (
    SELECT Name, ColumnValue, rn, cte_col1.ColumnID FROM cte_col1
    UNION ALL
    SELECT Name, ColumnValue, rn, cte_col2.ColumnID FROM cte_col2
    UNION ALL
    SELECT Name, ColumnValue, rn, cte_col3.ColumnID FROM cte_col3
    ) d
    GROUP BY d.Name, d.rn
    ORDER BY d.Name, d.rn
    OPTION (MAXDOP 1)
    

    结果成:

    Name    Column1 Column2 Column3
    Prod1   3   33  66
    Prod1   5   44  7
    Prod1   6   66  NULL
    Prod1   9   7   NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-04
      • 2017-02-14
      • 1970-01-01
      • 1970-01-01
      • 2021-08-13
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多