我在这里有一个问题,看起来有点像我在搜索中发现的一些问题,但是解决了稍微不同的问题,更重要的是那些在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_id
和important_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()以更优雅的方式来查找连续的条目。
感谢阅读。我为伪代码中的任何不必要的背景故障或错误道歉。
答案 0 :(得分:1)
好的,我想我认为这个问题非常好!
首先,我假设effective_date
列不会与user_id
重复。我认为如果不是这样的话,可以修改它 - 所以如果我们需要考虑到这一点,请告诉我。
该过程基本上将值和自连接表放在相等的user_id
和important_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)
我对使用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
通过这种方法,我仍然需要迭代结果,直到它什么都没有返回,但我想不出任何方法,这种方法比我的最后一步还要早。