拆分列值并移至行

时间:2019-03-01 07:23:00

标签: sql sql-server excel database

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

预先感谢 enter image description here

2 个答案:

答案 0 :(得分:0)

一些免责声明:

  • 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

答案 1 :(得分:0)

不幸的是,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是db <>小提琴。