在SQL中查找连续的日期对

时间:2011-08-23 18:28:48

标签: sql sql-server tsql sql-server-2000 date

我在这里有一个问题,看起来有点像我在搜索中发现的一些问题,但是解决了稍微不同的问题,更重要的是那些在SQL 2000中不起作用的问题。

我有一个非常大的表,其中包含大量冗余数据,我试图将其简化为有用的条目。它是一个历史表,以及它的工作方式,如果两个条目基本上是重复的,并且按日期排序时是连续的,后者可以删除。当从该条目的生效日期与下一个非重复条目之间的日期请求历史数据时,将使用前一条目中的数据。

数据看起来像这样:

id     user_id effective_date important_value useless_value
1      1       1/3/2007       3               0
2      1       1/4/2007       3               1
3      1       1/6/2007       NULL            1
4      1       2/1/2007       3               0
5      2       1/5/2007       12              1
6      3       1/1/1899       7               0

使用此样本集,如果user_idimportant_value相同,我们会考虑连续两行重复。从此示例集中,我们只删除id = 2的行,保留1-3-2007中的信息,显示important_value在1-6-2007更改,然后显示相关在2-1-2007再次改变。

我目前的方法很笨拙,而且我知道必须有更好的方法。我编写了一个脚本,它使用游标迭代user_id值(因为这会将巨大的表分成可管理的部分),并为该用户创建一个仅包含行的临时表。然后获取连续的条目,它接受临时表,在临时表中没有其他条目且两个日期之间有日期的条件下将其连接到自身。在下面的伪代码中,UDF_SameOrNull是一个函数,如果传入的两个值相同或者它们都是NULL,则返回1.

WHILE (@@fetch_status <> -1)
BEGIN
  SELECT * FROM History INTO #history WHERE user_id = @UserId

  --return entries to delete
  SELECT h2.id
  INTO #delete_history_ids
  FROM #history h1
  JOIN #history h2 ON
    h1.effective_date < h2.effective_date
    AND dbo.UDF_SameOrNull(h1.important_value, h2.important_value)=1
  WHERE NOT EXISTS (SELECT 1 FROM #history hx WHERE hx.effective_date > h1.effective_date and hx.effective_date < h2.effective_date)

  DELETE h1
  FROM History h1
  JOIN #delete_history_ids dh ON
    h1.id = dh.id 

  FETCH NEXT FROM UserCursor INTO @UserId
END 

它也循环遍历同一组重复,直到没有,因为取出行会创建新的连续对,这些对可能是欺骗。为简单起见,我把它留了下来。

不幸的是,我必须使用SQL Server 2000执行此任务,我很确定它不支持ROW_NUMBER()以更优雅的方式来查找连续的条目。

感谢阅读。我为伪代码中的任何不必要的背景故障或错误道歉。

2 个答案:

答案 0 :(得分:1)

好的,我想我认为这个问题非常好!

首先,我假设effective_date列不会与user_id重复。我认为如果不是这样的话,可以修改它 - 所以如果我们需要考虑到这一点,请告诉我。

该过程基本上将值和自连接表放在相等的user_idimportant_value以及之前的effective_date上。然后,我们在user_id上再做一次自我加入,通过验证在这两个记录之间没有effective_date记录,有效地检查上面的2个连接记录是否是连续的。

现在只是一个select语句 - 它应该选择要删除的所有记录。因此,如果您确认它返回了正确的数据,只需将select *更改为delete tcheck

如果您有疑问,请告诉我。

select 
    * 
from 
    History tcheck
    inner join History tprev
        on  tprev.[user_id] = tcheck.[user_id]
            and tprev.important_value = tcheck.important_value
            and tprev.effective_date < tcheck.effective_date
    left join History checkbtwn
        on  tcheck.[user_id] = checkbtwn.[user_id]
            and checkbtwn.effective_date < tcheck.effective_date
            and checkbtwn.effective_date > tprev.effective_date
where
    checkbtwn.[user_id] is null

答案 1 :(得分:0)

好的,伙计们,昨晚我做了一些思考,我想我找到了答案。我希望这可以帮助那些必须匹配连续数据对的人,并且出于某种原因也会陷入SQL Server 2000中。

我对使用ROW_NUMBER()的其他结果感到鼓舞,我使用了非常类似的方法,但是使用了标识列。

--create table with identity column
CREATE TABLE #history (
  id int, 
  user_id int, 
  effective_date datetime, 
  important_value int, 
  useless_value int,
  idx int IDENTITY(1,1)
)

--insert rows ordered by effective_date and now indexed in order
INSERT INTO #history
SELECT * FROM History 
WHERE user_id = @user_id
ORDER BY effective_date

--get pairs where consecutive values match
SELECT * 
FROM #history h1
JOIN #history h2 ON
  h1.idx+1 = h2.idx
WHERE h1.important_value = h2.important_value

通过这种方法,我仍然需要迭代结果,直到它什么都没有返回,但我想不出任何方法,这种方法比我的最后一步还要早。