SQL根据列的值删除表中的日期时间的冲突部分

时间:2015-12-16 17:08:47

标签: sql sql-server datetime relational-database sqldatetime

我有一张像

这样的表格
MemberID     MembershipStartDate           MembershipEndDate        type
=============================================================================
123          2010-01-01 10:00:00.000      2012-12-31 23:00:00.000   1
123          2011-01-01 21:00:00.000      2012-12-31 12:00:00.000   2
123          2013-05-01  9:00:00.000      2013-12-31  5:00:00.000   2
123          2014-01-01 14:00:00.000      2014-12-31  2:00:00.000   1
123          2014-01-01 11:00:00.000      2015-03-31  1:00:00.000   2

对于给定的成员和类型,时间不会发生冲突:对于类型1,将没有开始和结束行,这将与其他行一致,所以如果我有成员123类型1启动2010-01- 01 10:00:00.000并完成2012-12-31 23:00:00.000,我不能有会员123类型1开始2010-02-01 10:00:00.000完成2013-12-31 23:00:00.000自从范围是碰撞的(但我可以将其用于类型2)。这是我目前的表格。

我想要做的是删除相同MemberID的不同类型之间的时间冲突,因此对于memberID 123,如果类型2的行在2013-05-01 9:00:00.000开始并在2013年结束 - 12-31 5:00:00.000,类型1开始于2013-10-01 9:00:00.000并在2014-12-31 5:00:00.000结束,因为类型2的行首先开始(稍后开始是一个修剪过的),类型1的那个将修剪为:2013-12-31 5:00:00.000到2014-12-31 5:00:00.000,如你所见,新的开始日期该行是类型2行的完成日期。

最后,第一个表格将以

结尾
MemberID     MembershipStartDate           MembershipEndDate        type
=============================================================================
123          2010-01-01 10:00:00.000      2012-12-31 23:00:00.000   1
123          2012-12-31 23:00:00.000      2012-12-31 12:00:00.000   2
123          2013-05-01  9:00:00.000      2013-12-31  5:00:00.000   2
123          2014-01-01 14:00:00.000      2014-12-31  2:00:00.000   1
123          2014-12-31  2:00:00.000      2015-03-31  1:00:00.000   2

时间没有必要。

2 个答案:

答案 0 :(得分:2)

首先,我建议在表中添加一个auto_incrementing id字段,以便更容易引用每一行。

其次,使用自引用查询来查找有问题的记录(通常是我的愿望,生成更新sql)。

SELECT CONCAT("UPDATE <table> SET enddate = ", QUOTE(t2.startdate), " WHERE id = ", t1.id, ";") AS stmt
  #, t1.*, t2.* # uncomment this line to see the raw data.
FROM <table> AS t1
JOIN <table> AS t2 ON t1.member_id = t2.member_id
      AND t1.type = t2.type
      AND t1.id != t2.id # this makes sure that you dont connect a record to itself. If you didnt have an autoincrementing key, you would have a nasty OR chain to accomplish this
WHERE t1.enddate > t2.startdate 
  AND t1.startdate < t2.startdate;

如果您选择不使用和自动递增pk,则:

AND t1.id != t2.id
#becomes something like:
AND NOT (t1.enddate = t2.enddate AND t1.startdate = t2.startdate)

取决于实际的自然键(不包括您实际加入的部分)。

答案 1 :(得分:0)

查看已接受的答案和评论,以了解主要观点以及我从中做出的改变

SELECT t2.id, t2.code, MAX(case when t1.enddate > t2.startdate and t1.startdate < t2.startdate then t1.enddate else t2.startdate end), MAX(t2.enddate)
FROM @temporaryTable2 AS t2
LEFT JOIN @temporaryTable2 AS t1 ON t1.member_id = t2.member_id
      AND t1.Code != t2.Code
      AND t1.id != t2.id

GROUP BY t2.id, t2.code