我在几个表中有这样的结构:id,[...],validfrom,validto。
id
是一个数字,validfrom
和validto
列的类型为DATE。 任何指定日期不应导致每id
个帖子超过一个。
所以这是一个正确的例子:
id, validfrom, validto
1, 2000-01-01, 2000-02-20
1, 2000-02-21, 2000-03-02
1, 2000-03-03, 2099-12-31
但是,似乎某些日期会返回多个值。像这样的东西(这是腐败的数据):
id, validfrom, validto
1, 2001-01-01, 2001-02-20
1, 2001-01-15, 2001-03-02
1, 2001-03-03, 2099-12-31
所以在上面的例子中,2001-01-15和2001-02-20之间的任何日期都会返回两行。
我如何构建一个可以找到所有损坏帖子的脚本?
答案 0 :(得分:2)
只是为了找到它们,假设validfrom在每行中都小于有效值:
select a.*, b.*
from your_table a
join your_table b
on (a.id = b.id and
--overlapping
greatest(a.validfrom, b.validfrom) <= least(a.validto, b.validto) and
--exclude join the same row.
a.rowid <> b.rowid
)
这只是找到相交的间隔,因为不同的间隔的valid_from大于另一个的valid_to。
UPDATE
:我替换了条件not (a.validto=b.validto and a.validfrom=b.validfrom)
与
a.rowid<> b.rowid
因为它现在会报告重复的行。 (谢谢沃尔菲)
答案 1 :(得分:2)
找到重叠的时间跨度是一场噩梦。很容易出错,而且我所知道的并没有简单而好的解决方案。从理论上讲,Oracle已使用数据类型WM_PERIOD
解决了这个问题,数据类型可能会也可能不会在您的数据库中安装/可用。但它也不是美女:
SELECT *
FROM your_table a JOIN your_table b USING (id)
WHERE a.rowid < b.rowid
AND wm_overlaps(wm_period(a.validfrom, a.validto),
wm_period(b.validfrom, b.validto))=1;
1 2001-01-01 2001-02-20 2001-01-15 2001-03-02
答案 2 :(得分:1)
这将查找重叠的行和重复的行:
select *
from YourTable yt1
where -- Overlapping rows exist
exists
(
select *
from YourTable yt2
where yt1.id = yt2.id
-- Rows overlap
and yt1.validfrom <= yt2.validto
and yt2.validfrom <= yt1.validto
-- Rows must be distinct
and yt1.rowid <> yt2.rowid
)