将多行合并为一行(SQL)

时间:2016-04-05 17:06:49

标签: sql-server merge

我正在开发一个项目来为不同的订单创建SLA。要做到这一点,我需要将多行合并为一行,尽管有时它会超过1行。以下是当前数据的设置方式:

OrderNumber | Stage1 | Stage2 | Stage3 | Stage4 |
=================================================
1           |1/1/2016|*NULL*  |*NULL*  | *NULL*
1           |*NULL*  |2/1/2016|*NULL*  | *NULL*
1           |*NULL*  |*NULL*  |3/1/2016| *NULL*
1           |*NULL*  |*NULL*  |*NULL*  | 4/1/2016
1           |*NULL*  |5/1/2016|*NULL*  | *NULL*

我希望看到数据的方式是这样的:

OrderNumber | Stage1 | Stage2 | Stage3 | Stage4 |
=================================================
1           |1/1/2016|2/1/2016|3/1/2016| 4/1/2016
1           |1/1/2016|5/1/2016|*NULL*  | *NULL*

OR

OrderNumber | Stage1 | Stage2 | Stage3 | Stage4 |
=================================================
1           |1/1/2016|2/1/2016|3/1/2016| 4/1/2016
1           |*NULL*  |5/1/2016|*NULL*  | *NULL*

我看到两个问题,1)将多行合并到一行中2)如果一个值多次显示在一列中,则将其显示在一个新行中(理想情况下,前一个阶段中出现的值)列,但这不是必需的)。

我找到的最接近的解决方案是:Merge two rows in SQL,但它不适用于此问题。

非常感谢任何帮助。

编辑更新的标签

3 个答案:

答案 0 :(得分:0)

我使用window functions使用SQL Server 2012解决了这个问题。由于MySQL还支持窗口功能,因此它与哪个数据库无关。如果MySQL不支持CTE,您可以将其替换为派生表。

有4个阶段,所以我们需要4个加入。

;with cte as (
select t1.OrderNumber, t1.Stage1, t2.Stage2, t3.Stage3, t4.Stage4
, LAG(t1.Stage1) over (partition by t1.OrderNumber order by t1.Stage1) AS Prev1
, LAG(t2.Stage2) over (partition by t2.OrderNumber order by t2.Stage2) AS Prev2
, LAG(t3.Stage3) over (partition by t3.OrderNumber order by t3.Stage3) AS Prev3
, LAG(t4.Stage4) over (partition by t4.OrderNumber order by t4.Stage4) AS Prev4
from #t t1
  inner join #t t2 on t2.OrderNumber = t1.OrderNumber and t2.Stage2 is not null
  inner join #t t3 on t3.OrderNumber = t1.OrderNumber and t3.Stage3 is not null
  inner join #t t4 on t4.OrderNumber = t1.OrderNumber and t4.Stage4 is not null
where t1.Stage1 is not null
)
select OrderNumber
, IIF(Stage1 <> Prev1 or Prev1 is null, Stage1, Null) AS Stage1 
, IIF(Stage2 <> Prev2 or Prev2 is null, Stage2, Null) AS Stage2
, IIF(Stage3 <> Prev3 or Prev3 is null, Stage3, Null) AS Stage3
, IIF(Stage4 <> Prev4 or Prev4 is null, Stage4, Null) AS Stage4
from cte

将#t替换为您的表名

结果:

+-------------+------------+------------+------------+------------+
| OrderNumber |   Stage1   |   Stage2   |   Stage3   |   Stage4   |
+-------------+------------+------------+------------+------------+
|           1 | 2016-01-01 | 2016-01-02 | 2016-01-03 | 2016-01-04 |
|           1 | NULL       | 2016-01-05 | NULL       | NULL       |
+-------------+------------+------------+------------+------------+

答案 1 :(得分:0)

您可以取消数据,然后再次转动

SELECT OrderNumber, [Stage1], [Stage2], [Stage3], [Stage4] 
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Vals ORDER BY Val) Rn FROM 
    Table1 t
    UNPIVOT
    (
        Val
        FOR Vals IN ([Stage1], [Stage2], [Stage3], [Stage4])
    ) up
) t
PIVOT 
(
    MAX(Val)
    FOR Vals IN ([Stage1], [Stage2], [Stage3], [Stage4])
) p

答案 2 :(得分:0)

with data as (
    select
        OrderNumber, Stage1, Stage2, Stage3, Stage4,
        row_number() over (
            partition by OrderNumber
            order by
                case when Stage1 is not null then 0 else 1 end, Stage1,
                case when Stage2 is not null then 0 else 1 end, Stage2,
                case when Stage3 is not null then 0 else 1 end, Stage3,
                case when Stage4 is not null then 0 else 1 end, Stage4) rn,
        row_number() over (
            partition by OrderNumber
            order by case when Stage1 is not null then 0 else 1 end, Stage1) r1,
        row_number() over (
            partition by OrderNumber
            order by case when Stage2 is not null then 0 else 1 end, Stage2) r2,
        row_number() over (
            partition by OrderNumber
            order by case when Stage3 is not null then 0 else 1 end, Stage3) r3,
        row_number() over (
            partition by OrderNumber
            order by case when Stage4 is not null then 0 else 1 end, Stage4) r4
    from T
)
select
    OrderNumber, s1.Stage1, s2.Stage2, s3.Stage3, s4.Stage4
from
    data d
    cross apply (select d1.Stage1 from data d1 where d1.r1 = d.rn) s1(Stage1)
    cross apply (select d2.Stage2 from data d2 where d2.r2 = d.rn) s2(Stage2)
    cross apply (select d3.Stage3 from data d3 where d3.r3 = d.rn) s3(Stage3)
    cross apply (select d4.Stage4 from data d4 where d4.r4 = d.rn) s4(Stage4)
where
    coalesce(s1.Stage1, s2.Stage2, s3.Stage3, s4.Stage4) is not null