【问题标题】:Efficient Date Comparisons in SQLSQL 中的高效日期比较
【发布时间】:2012-11-27 00:30:11
【问题描述】:

我希望这个问题能提供所有必要的信息,但如果有任何不清楚的地方,请提出更多要求。这是我关于堆栈溢出的第一个问题,所以请多多包涵。

我在 SQL Server 2005 上运行此查询。

我有一个包含 4 个字段的大型派生数据集(稍后我将提供一个小子集); ID, 年, 开始日期, 结束日期

在此数据集中,ID 可能(正确地)以不同的日期组合出现多次。

我的问题是有什么方法可以确定记录是否是“新的”,即它的开始日期不在同一 ID 的任何其他记录的开始日期和结束日期之间。

以下面的数据集为例(我希望这个表正确!);

+----+--------+------------+------------+ |身份证 |年份 |开始日期 |结束日期 | +----+--------+------------+------------+ | 1 | 2007 | 2007 年 1 月 1 日 | 2007 年 10 月 10 日 | | 1 | 2007 | 2007 年 1 月 1 日 | 2007 年 5 月 4 日 | | 1 | 2007 | 2007 年 5 月 4 日 | 2007 年 8 月 10 日 | | 1 | 2007 | 2007 年 15 月 10 日 | 20/10/2007 | | 1 | 2007 | 2007 年 10 月 25 日 | 2008 年 1 月 1 日 | | 2 | 2007 | 2007 年 1 月 1 日 | 2008 年 1 月 1 日 | | 2 | 2008 | 2008 年 1 月 1 日 | 2008 年 7 月 15 日 | | 2 | 2008 | 2008 年 10 月 6 日 | 2009 年 1 月 1 日 | +----+--------+------------+------------+

如果我们说 2007 年之前什么都不存在,那么第 1 行和第 6 行在当时是“新的”。

第 2、3、7 和 8 行不是“新的”,因为它们要么连接上一条记录的末尾,要么重叠形成一个连续的日期周期(以第 6 行和第 7 行为例,01/ 之间没有“中断” 01/2008 和 01/01/2009)

第 4 行和第 5 行将被视为新记录,因为它不直接附加到 ID 1 的上一期间的末尾或与任何其他期间重叠。

目前要获得这个数据集,我必须将所有数据放入临时表中,然后将它们连接到各个字段中以删除我不想要的记录。

首先,我删除 startdate 等于该 ID 的另一行的 enddate 的行(这将删除第 3 行和第 7 行)

然后我删除开始日期介于该 ID 的其他记录的开始日期和结束日期之间的行(这将删除第 2 行和第 8 行)

这将使我将第 1、4、5 和 6 行作为正确的“新”记录。

是否有更有效的方法来执行此操作,例如在某种循环、CTE 或 cough 光标中?

如上所述,如果有任何不清楚的地方,请不要犹豫,我会尽力为您提供您要求的信息。

【问题讨论】:

  • 选择表格并单击格式为代码图标以保留您的间距。
  • 第 6 行应该是 ID 1 而不是 ID 2?
  • 嗨,Beth,第 6 行不应该是 ID 2。一个 ID 可以出现多年,在此示例中,第 7 行不会被视为新的,因为它的开始日期与第 6 行的结束日期匹配即使这是在上一年

标签: sql-server tsql sql-server-2005


【解决方案1】:

试试

;with cte as
(
    Select *, row_number() over (partition by id order by startdate) rn from yourtable
)
select distinct t1.* 
from cte t1
     left join cte t2 
     on t1.ID = t2.ID
     and t1.EndDate>=t2.StartDate and t1.StartDate<=t2.EndDate
     and t1.rn<>t2.rn
where t2.ID is null
or t1.rn=1

【讨论】:

  • Podiluska,非常感谢您的回复。我将不得不查找您对分区的使用(我以前没有使用过),并在针对我的更大数据集进行测试后回复您。如果我在完成后对它的工作原理有任何疑问,我会回复你
  • @NeilRutland 上面有两个目的 - 首先是找到开始条目,其次是标识 ID 组内的记录。
【解决方案2】:

这应该可以工作,如果每行都有一个唯一标识符:

select * from 
tbl t3 
left outer join
(
select distinct t1.id as id_inside, t1.recno as recno_inside
from 
tbl t1 inner join 
tbl t2 on
t1.id = t2.id and
(t1.startdate <> t2.startdate or t1.enddate <> t2.enddate) and
(t1.startdate >= t2.startdate and t1.enddate <= t2.enddate)
 ) t4 on
t3.id = t4.id_inside and
t3.recno = t4.recno_inside
where
id_inside is null and
recno_inside is null

sqlfiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-06
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多