SQL Server:使用条件将2行合并为1

时间:2016-03-11 08:13:47

标签: sql sql-server sql-server-2008 sql-server-2008-r2

我有一个返回此结果的查询

-----------------------------------------------------------------
|ID |ID1|ID2|IDP|IDC|IDA|START_DATE         |END_DATE           |
-----------------------------------------------------------------
|10 |2  |1  |10 |152|15 |1900-01-01 08:10:00|1900-01-01 09:10:00|
|10 |2  |1  |20 |152|12 |1900-01-01 09:10:00|1900-01-01 10:10:00|
|10 |2  |1  |30 |152|11 |1900-01-01 10:10:00|1900-01-01 11:10:00|
|10 |2  |1  |10 |152|15 |1900-01-01 11:10:00|1900-01-01 12:10:00|
|10 |2  |1  |10 |152|15 |1900-01-01 12:10:00|1900-01-01 13:10:00|
-----------------------------------------------------------------

我需要合并最后两行,因为第四行的END_DATE等于第五行的START_DATE。其他行都没问题,他们必须像那样。所以我想得到这个结果。

-----------------------------------------------------------------
|ID |ID1|ID2|IDP|IDC|IDA|START_DATE         |END_DATE           |
-----------------------------------------------------------------
|10 |2  |1  |10 |152|15 |1900-01-01 08:10:00|1900-01-01 09:10:00|
|10 |2  |1  |20 |152|12 |1900-01-01 09:10:00|1900-01-01 10:10:00|
|10 |2  |1  |30 |152|11 |1900-01-01 10:10:00|1900-01-01 11:10:00|
|10 |2  |1  |10 |152|15 |1900-01-01 11:10:00|1900-01-01 13:10:00|
-----------------------------------------------------------------

第四和第五行

-----------------------------------------------------------------
|10 |2  |1  |10 |152|15 |1900-01-01 11:10:00|1900-01-01 12:10:00|
|10 |2  |1  |10 |152|15 |1900-01-01 12:10:00|1900-01-01 13:10:00|
-----------------------------------------------------------------

他们必须只成为一个

-----------------------------------------------------------------
|10 |2  |1  |10 |152|15 |1900-01-01 11:10:00|1900-01-01 13:10:00|
-----------------------------------------------------------------

我该怎么做?

2 个答案:

答案 0 :(得分:0)

假设您的输出查询是一个表,这可能有效:

(@ tmp - 返回结果的表格)

select   t.id,
         t.id1,
         t.id2,
         t.idp,          t.idc,
         t.ida,
         t.startDate,
         t2.enddate  from @tmp t left outer join @tmp t2 on t2.startDate = t.enddate where t2.id is not null

但正如Joe Taras所说,请添加您所写的内容或存储数据的表格。

答案 1 :(得分:0)

在SQL Server 2012+中,使用LAG函数可以更有效地完成它。

在SQL Server 2008中,如果数据量很大,我会使用游标。

以下基于集合的方法有效,但大表可能会很慢。

示例数据

DECLARE @T TABLE 
    (ID int, ID1 int, ID2 int, IDP int, IDC int, IDA int, 
    START_DATE datetime2(0), END_DATE datetime2(0));

INSERT INTO @T
    (ID, ID1, ID2, IDP, IDC, IDA, START_DATE, END_DATE)
VALUES
    (10, 2, 1, 10, 152, 15, '1900-01-01 08:10:00', '1900-01-01 09:10:00'),
    (10, 2, 1, 20, 152, 12, '1900-01-01 09:10:00', '1900-01-01 10:10:00'),
    (10, 2, 1, 30, 152, 11, '1900-01-01 10:10:00', '1900-01-01 11:10:00'),
    (10, 2, 1, 10, 152, 15, '1900-01-01 11:10:00', '1900-01-01 12:10:00'),
    (10, 2, 1, 10, 152, 15, '1900-01-01 12:10:00', '1900-01-01 13:10:00');

<强>查询

CTE_Merged将表格与所有ID列以及开始+结束日期连接起来。它将为每对应合并的行生成一行。

CTE_Join将原始表格与CTE_Merged两次加入。首先 - 获取应保留的行的FinalEndDate; second - 过滤掉合并对的第二行(使用WHERE CTE_Join.M2END_DATE IS NULL)。

逐步运行此查询并检查中间结果以了解其工作原理。

WITH
CTE_Merged
AS
(
    SELECT
        T1.ID
        ,T1.ID1
        ,T1.ID2
        ,T1.IDP
        ,T1.IDC
        ,T1.IDA
        ,T1.START_DATE
        ,T2.END_DATE AS MergedEndDate
    FROM
        @T AS T1
        INNER JOIN @T AS T2
            ON  T1.ID  = T2.ID
            AND T1.ID1 = T2.ID1
            AND T1.ID2 = T2.ID2
            AND T1.IDP = T2.IDP
            AND T1.IDC = T2.IDC
            AND T1.IDA = T2.IDA
            AND T1.END_DATE = T2.START_DATE
)
,CTE_Join
AS
(
    SELECT
        T.ID
        ,T.ID1
        ,T.ID2
        ,T.IDP
        ,T.IDC
        ,T.IDA
        ,T.START_DATE
        ,T.END_DATE
        ,M1.START_DATE AS M1START_DATE
        ,M1.MergedEndDate AS M1END_DATE
        ,ISNULL(M1.MergedEndDate, T.END_DATE) AS FinalEndDate
        ,M2.START_DATE AS M2START_DATE
        ,M2.MergedEndDate AS M2END_DATE
    FROM
        @T AS T
        LEFT JOIN CTE_Merged AS M1
            ON  T.ID  = M1.ID
            AND T.ID1 = M1.ID1
            AND T.ID2 = M1.ID2
            AND T.IDP = M1.IDP
            AND T.IDC = M1.IDC
            AND T.IDA = M1.IDA
            AND T.START_DATE = M1.START_DATE
        LEFT JOIN CTE_Merged AS M2
            ON  T.ID  = M2.ID
            AND T.ID1 = M2.ID1
            AND T.ID2 = M2.ID2
            AND T.IDP = M2.IDP
            AND T.IDC = M2.IDC
            AND T.IDA = M2.IDA
            AND T.END_DATE = M2.MergedEndDate
)
SELECT
    CTE_Join.ID
    ,CTE_Join.ID1
    ,CTE_Join.ID2
    ,CTE_Join.IDP
    ,CTE_Join.IDC
    ,CTE_Join.IDA
    ,CTE_Join.START_DATE
    ,CTE_Join.FinalEndDate
FROM CTE_Join
WHERE
    CTE_Join.M2END_DATE IS NULL
;

<强>结果

+----+-----+-----+-----+-----+-----+---------------------+---------------------+
| ID | ID1 | ID2 | IDP | IDC | IDA |     START_DATE      |    FinalEndDate     |
+----+-----+-----+-----+-----+-----+---------------------+---------------------+
| 10 |   2 |   1 |  10 | 152 |  15 | 1900-01-01 08:10:00 | 1900-01-01 09:10:00 |
| 10 |   2 |   1 |  20 | 152 |  12 | 1900-01-01 09:10:00 | 1900-01-01 10:10:00 |
| 10 |   2 |   1 |  30 | 152 |  11 | 1900-01-01 10:10:00 | 1900-01-01 11:10:00 |
| 10 |   2 |   1 |  10 | 152 |  15 | 1900-01-01 11:10:00 | 1900-01-01 13:10:00 |
+----+-----+-----+-----+-----+-----+---------------------+---------------------+