2013-05-31 158 views
1

我有一個包含日期和一列的表,它告訴它是否是「連接」的一系列日期中的第一個日期。 實施例SQL:獲取一系列日期中的最後一個日期

╔═══════════╦════════════╦═══════╗ 
║ person_id ║ DATE ║ FIRST ║ 
╠═══════════╬════════════╬═══════╣ 
║   1 ║ 2013-05-31 ║  1 ║ 
║   1 ║ 2013-06-01 ║  0 ║ 
║   1 ║ 2013-06-02 ║  0 ║ 
║  15 ║ 2013-07-08 ║  1 ║ 
║  15 ║ 2013-07-09 ║  0 ║ 
║   1 ║ 2013-07-30 ║  1 ║ 
║   1 ║ 2013-07-31 ║  0 ║ 
║   1 ║ 2013-08-01 ║  0 ║ 
╚═══════════╩════════════╩═══════╝ 

我需要由用於開始日期和結束日期爲每個系列的柱的新表。例如:

╔═══════════╦════════════╦════════════╗ 
║ person_id ║ START_DATE ║ END_DATE ║ 
╠═══════════╬════════════╬════════════╣ 
║   1 ║ 2013-05-31 ║ 2013-06-02 ║ 
║  15 ║ 2013-07-08 ║ 2013-07-09 ║ 
║   1 ║ 2013-07-30 ║ 2013-08-01 ║ 
╚═══════════╩════════════╩════════════╝ 

有沒有可能不使用while循環? 我嘗試了一個while循環,但它的速度很慢。該表大約有100 000條記錄。

我嘗試的循環看起來類似下面:

IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('dbo.temp_table')) 
drop table temp_table; 
go 

SELECT 
[person_id], 
[date], 
[first], 
0 AS Processed, 
N = ROW_NUMBER() OVER (ORDER BY p_id, datum) 
INTO temp_table 
FROM [person_dates] 
ORDER BY person_id, date 
go 

declare @N int 
declare @N2 int 
declare @P_ID int 
declare @DATE varchar(10) 
declare @DATE2 varchar(10) 
declare @start_date datetime 
declare @end_date datetime 

While (Select Count(*) From temp_table Where Processed = 0 AND first=1) > 0 
Begin 
    Select @N=N,@P_ID=person_id, @DATE=date From temp_table Where Processed = 0 AND first=1 ORDER BY N 
    set @start_date = CAST(@DATE as datetime) 
    set @[email protected] 
    while (SELECT COUNT(*) FROM temp_table Where Processed = 0 AND first<>1 and 
      CAST(date as datetime) = dateadd(day,1,CAST(@DATE2 as datetime)) and [email protected]_ID) > 0 
    Begin 
     Select @N2=N,@DATE2=date From temp_table Where Processed = 0 AND first<>1 and 
      CAST(date as datetime) = dateadd(day,1,CAST(DATE2 as datetime)) and [email protected]_ID ORDER BY N 
     Update temp_table Set Processed = 1 Where N = @N2  
    End 
    set @end_date=CAST(@DATE2 as datetime) 
    Update temp_table Set Processed = 1 Where N = @N 
End 
go 

IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id('dbo.temp_table')) 
drop table temp_table; 
go 
+0

爲什麼有兩排用'爲person_id = 1'在結果集中? –

+0

什麼DBMS? SQL Server? – Kermit

+0

@AndreyGordeev - 是一個如何確定結束日期08-01是否對應於07-30或05-31? – mikey

回答

1

下面是一個簡單的觀察。如果您執行「第一個」列的累計總和,那麼您將擁有一個定義每個組的列。

在某些數據庫中,您可以使用窗口/分析函數進行累計求和。在其他情況下,你需要一個相關的子查詢。

select person_id, min(date) as start_date, max(date) as end_date 
from (select pd.*, 
      (select sum(first) 
       from person_dates pd2 
       where pd2.person_id = pd.person_id and 
        pd2.date <= pd.date 
      ) as cumfirst 
     from person_dates pd 
    ) pd 
group by person_id, cumfirst; 

使用ANSI標準的累積和語法,你可以這樣寫:

select person_id, min(date) as start_date, max(date) as end_date 
from (select pd.*, 
      sum(first) over (partition by person_id order by date) as cumFirst 
     from person_dates pd 
    ) pd 
group by person_id, cumfirst; 
+0

第一個(與子查詢)在MS SQL中像一個魅力一樣工作。 謝謝! – supremo

1

你可以用一個SQL語句做到這一點,使用自加盟,

Select distinct person_id, s.Date startDate, 
    e.Date endDate 
From person_dates s 
    Left Join n -- find next first if one exists 
    On n.person_id = s.person_id   
     And First = 1 
     And n.Date = 
      (Select Min(date) from person_dates 
      Where person_id = s.person_id 
       And First = 1 
       And date > s.Date) 
    Join person_dates e -- find last row before next first 
    On e.person_id = s.person_id 
     And e.Date = 
      (Select Max(date) from person_dates 
      where person_id = s.person_id 
       And date > s.Date 
       And date < Coalesce(n.Date, date+1)) 
Where s.First = 1 
相關問題