SQL 根据列的值删除 table 中日期时间的冲突部分
SQL remove colliding part of datetimes in a table according to value of a column
我有一个table喜欢
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)。这是我目前的 table.
我想要做的是消除相同 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 [=29= .000,如您所见,该行的新开始日期是类型 2 的行的结束日期。
最后,第一个table将以
结束
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
时间顺序不需要。
首先,我建议在 table 中添加一个 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)
取决于自然键实际是什么(不包括您实际加入的部分)。
查看已接受的答案和评论,了解主要思想以及我从中更改的内容
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
我有一个table喜欢
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)。这是我目前的 table.
我想要做的是消除相同 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 [=29= .000,如您所见,该行的新开始日期是类型 2 的行的结束日期。
最后,第一个table将以
结束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
时间顺序不需要。
首先,我建议在 table 中添加一个 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)
取决于自然键实际是什么(不包括您实际加入的部分)。
查看已接受的答案和评论,了解主要思想以及我从中更改的内容
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