2015-06-19 70 views
1

我使用SQL Server和我有如下表:如果日期按順序,如何基於日期列合併SQL中的行?

ID  Res_ID Start  End 
--------------------------------------- 
5917 9742 2015-08-11 2015-08-11 
5918 9742 2015-08-12 2015-08-12 
5919 9837 2015-09-07 2015-09-07 
5920 9788 2015-09-09 2015-09-09 
5921 9788 2015-09-10 2015-09-10 
5922 9788 2015-09-11 2015-09-11 
5923 9788 2015-09-11 2015-09-11 
5924 9788 2015-10-01 2015-10-01 
5925 9788 2015-10-02 2015-10-02 

我嘗試在日期順序合併行。在我的例子中,查詢後我應該得到下面的表格:

ID  Res_ID Start  End 
---------------------------------------- 
XXXX 9742 2015-08-11 2015-08-12 
XXXX 9837 2015-09-07 2015-09-07 
XXXX 9788 2015-09-09 2015-09-11 
XXXX 9788 2015-10-01 2015-10-02 

我真的不是最後的[ID]。

我不知道該怎麼做... 你能幫我做這個手術嗎?

編輯:天必須是連續的,並在源表中開始=結束。我更新了我的例子。

+1

結束日期應該是09-10和09-11而不是10-09和11-09? –

+0

@JamesZ確實,我的不好。我更新了它,謝謝! – Alex

回答

2

這聽起來像一個缺口和島嶼問題。假設你的範圍總是隻有1天,你可以用行號來計算從組的第一天到這一行的距離。所有那些具有相同的距離(如扣除行號之日起結束到當天)屬於同一個島上,否則這是一個缺口:

select 
    min(id) as id, 
    res_id, 
    min([start]) as [start], 
    max([end]) as [end] 
from (
    select 
     id, 
     res_id, 
     [start], 
     [end], 
     dateadd(day, -RN, [end]) as groupdate 
    from 
    (
     select 
     id, 
     res_id, 
     [start], 
     [end], 
     row_number() over (partition by res_id order by [start] asc) as RN 
     from 
     table1 
    ) X 
) Y 
group by 
    res_id, 
    groupdate 

您可以在SQL Fiddle檢查。我在日期之間添加了一行額外的行,以確保日期與其他日期沒有分組。

+0

非常令人印象深刻,非常感謝! – Alex

0

你可以使用這樣的事情:

SELECT DISTINCT 
Min([Start]) OVER(Partition By Res_ID Order By [Start] Asc) as 'Start', 
Max([End]) OVER(Partition By Res_ID Order By [End] Desc) as 'End' 
FROM sometable 

這完美的作品。但是爲了使它起作用,你不能選擇第一個ID,因爲它在你的例子中被壓制了,所以它無用。

SQL FIDDLE

+1

這會讓你走上正確的道路。您的實際查詢可能涉及從選擇中選擇以獲得您想要的內容。 – TheMadDBA

+0

@TheMadDBA我已經調整並測試了它,現在它工作正常。 –

+0

我認爲他們也需要所有其他值......並且可能只有當日期是連續的(相隔1天)時纔有效?但是至少你應該讓它們在正確的路徑上加上窗口函數。 – TheMadDBA

0

對於您的示例提供的精確數據集,你可以,如果你RES_ID的值的變化到另一個RES_ID後出現使用MIN和MAX ...

SELECT 
    DerivedFirstEvents.[ID], 
    DerivedFirstEvents.Res_ID, 
    DerivedTotalDurations.[Start], 
    DerivedTotalDurations.[End] 
FROM 
    (
    SELECT 
     MIN([ID]) AS [ID], 
     Res_ID 
    FROM 
     SampleTable 
    GROUP BY 
     Res_ID 
    ) DerivedFirstEvents 
    LEFT OUTER JOIN 
    (
    SELECT 
     Res_ID, 
     MIN(Start) AS [Start], 
     MAX([End]) AS [End] 
    FROM 
     SampleTable 
    GROUP BY 
     Res_ID 
    ) DerivedTotalDurations ON DerivedFirstEvents.Res_ID = DerivedTotalDurations.Res_ID 

然而, ,像這樣...

ID  Res_ID Start  End 
--------------------------------------- 
5917 9742 2015-08-11 2015-08-11 
5918 9742 2015-08-12 2015-08-12 
5919 9837 2015-09-07 2015-09-07 
5920 9788 2015-09-09 2015-09-09 
5921 9788 2015-09-10 2015-10-09 
5922 9788 2015-09-11 2015-11-09 
5923 9742 2015-10-11 2015-10-11 --new line 
5924 9742 2015-10-12 2015-10-12 --new line 

...你的結果爲9742 RES_ID設置將出現開始就2015年8月11日,結束於2015年10月12日,這可能不是所期望的結果。如果是這種情況,我認爲你會有一個更復雜的解決方案,包括在記錄集中運行遊標並檢查每行以設置一些變量,然後有條件地將它們插入臨時表中,然後從該臨時表中選擇表完成後。

0

試試這個!

IF OBJECT_ID(N'tempdb..#t') IS NOT NULL DROP TABLE #t 

;WITH u ([id],[Res_ID],[Start],[End]) AS (SELECT N'5917' AS [id], N'9742' AS [Res_ID], N'2015-08-11' AS [Start], N'2015-08-11' AS [End] 
UNION SELECT N'5918' AS [id], N'9742' AS [Res_ID], N'2015-08-12' AS [Start], N'2015-08-12' AS [End] 
UNION SELECT N'5919' AS [id], N'9837' AS [Res_ID], N'2015-09-07' AS [Start], N'2015-09-07' AS [End] 
UNION SELECT N'5920' AS [id], N'9788' AS [Res_ID], N'2015-09-09' AS [Start], N'2015-09-09' AS [End] 
UNION SELECT N'5921' AS [id], N'9788' AS [Res_ID], N'2015-09-10' AS [Start], N'2015-10-09' AS [End] 
UNION SELECT N'5922' AS [id], N'9788' AS [Res_ID], N'2015-09-11' AS [Start], N'2015-11-09' AS [End]) 
SELECT 
    u.[id], 
    u.[Res_ID], 
    u.[Start], 
    u.[End] 
INTO #t 
FROM u 

SELECT 
    MIN(id) AS id, [Res_ID], 
    (SELECT MIN([Start]) FROM #t AS sub WHERE sub.[Res_ID] = t.[Res_ID]) AS [Start], 
    (SELECT MAX([End]) FROM #t AS sub WHERE sub.[Res_ID] = t.[Res_ID]) AS [End] 
FROM #t AS t 
GROUP BY [Res_ID] 
ORDER BY [Res_ID]