【问题标题】:SQL remove colliding part of datetimes in a table according to value of a columnSQL根据列的值删除表中日期时间的冲突部分
【发布时间】:2015-12-16 17:08:47
【问题描述】:

我有一张这样的桌子

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,如您所见,新的开始日期for the row 是类型 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

时间没有必要按顺序排列。

【问题讨论】:

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


    【解决方案1】:

    首先,我建议在表中添加一个 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 和最佳答案,因为我从答案中获取了想法和大部分代码(实际上几乎相同,只是更正并更改了更新)。这不符合我的预期,因为这正在更改结束日期,而我想更改开始日期。另外,我更喜欢它而不更新表格。至于其余的,我将发布的答案是一样的。
    【解决方案2】:

    查看已接受的答案和 cmets 以了解主要思想以及我从中更改的内容

    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
    

    【讨论】:

      猜你喜欢
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多