2011-03-04 24 views
1

考虑以下几点:SQL - 需要确定隐式结束日期提供的开始日期

CREATE TABLE Members 
(
    MemberID CHAR(10) 
    , GroupID CHAR(10) 
    , JoinDate DATETIME 
) 

INSERT Members VALUES ('1', 'A', 2010-01-01) 
INSERT Members VALUES ('1', 'C', 2010-09-05) 
INSERT Members VALUES ('1', 'B', 2010-04-15) 
INSERT Members VALUES ('1', 'B', 2010-10-10) 
INSERT Members VALUES ('1', 'A', 2010-06-01) 
INSERT Members VALUES ('1', 'D', 2001-11-30) 

会是什么,从这个表中选择的最佳方式,确定隐含“LeaveDate”,产生了下面的数据集:

MemberID GroupID JoinDate LeaveDate 
1  A  2010-01-01 2010-04-14 
1  B  2010-04-15 2010-05-31 
1  A  2010-06-01 2010-09-04 
1  C  2010-09-05 2010-10-09 
1  B  2010-10-10 2010-11-29 
1  D  2010-11-30 NULL 

正如您所看到的,假设成员没有失效。每个成员身份期间的[LeaveDate]假定为下一个按时间顺序排列的[JoinDate]之前一天,该成员可以在不同组中找到该成员。当然,这是我的实际问题的简单说明,其中包括更多的分类/分组列和数千个不同成员,其中[JoinDate]值的存储顺序不特定。

+0

难道他们都应该有相同的'MemberID'? 'LeaveDate'如何确定? – FrustratedWithFormsDesigner 2011-03-04 14:59:33

回答

2

也许这样的事情?自加入,并选择大于当前行的加入日期的最小加入日期 - 即离职日期加1。从它减去一天。

您可能需要调整特定RDBMS的日期算术。

SELECT 
     m1.* 
    , MIN(m2.JoinDate) - INTERVAL 1 DAY AS LeaveDate 
FROM 
    Members m1 
LEFT JOIN 
    Members m2 
ON m2.MemberID = m1.MemberID 
AND m2.JoinDate > m1.JoinDate 
GROUP BY 
     m1.MemberID 
    , m1.GroupID 
    , m1.JoinDate 
ORDER BY 
     m1.MemberID 
    , m1.JoinDate 
+0

这个效果很好。谢谢。 – 2011-03-04 20:10:34

0

标准(ANSI)SQL解决方案:

 
SELECT memberid, 
     groupid, 
     joindate, 
     lead(joindate) OVER (PARTITION BY memberid ORDER BY joindate ASC) AS leave_date 
FROM members 
ORDER BY joindate ASC 
+0

我正在拍摄ANSI标准代码,但是在MSSQL 2008中似乎没有支持LEAD()OVER()。感谢您的建议。看起来像一个非常优雅的解决方案。 – 2011-03-04 20:10:13

+0

@ Rich.Carpenter:你没有说明你的DBMS和所有DBMS都支持lead()和lag();) – 2011-03-04 20:47:13

相关问题