我有一个SQL查询表产品,以检查产品记录重叠。 在大多数情况下,查询工作,除了以下的罚款。
select * from products where
product_reg_no = 'AL-NAPT'
and (to_date('14-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001')
or to_date('31-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001'))
如何使这个查询来捕获所有记录都重叠的部分或全部?
如果需要,我可以提供样品记录表结构。
谢谢
更新1
我已经加入表结构和记录这里或如下:
create table products
(product_reg_no varchar2(32),
start_date date,
end_date date);
Insert into products
(product_reg_no, START_DATE, END_DATE)
Values
('AL-NAPT', TO_DATE('08/14/2012', 'MM/DD/YYYY'), TO_DATE('08/31/2012', 'MM/DD/YYYY'));
Insert into products
(product_reg_no, START_DATE, END_DATE)
Values
('AL-NAPT', TO_DATE('08/27/2012', 'MM/DD/YYYY'), TO_DATE('08/30/2012', 'MM/DD/YYYY'));
COMMIT;
的第一个记录是从14 2012年8月,8 月,31 2012是与从八月第二记录,27 2012至8月,30 2012重叠。 所以,我怎么能修改我的查询来获取重叠?
请参见确定两个日期范围是否重叠 。
您需要评估以下,或使用就可以了轻微变异<=
而非<
,也许是:
Start1 < End2 AND Start2 < End1
既然你有一个表的工作,你需要有一个自联接:
SELECT p1.*, p2.*
FROM products p1
JOIN products p2
ON p1.product_reg_no != p2.product_reg_no
AND p1.start < p2.end
AND p2.start < p1.end;
在不相等条件确保你没有得到与自己配对(虽然创纪录的<
条件也保证了,但如果你使用<=
在不相等的条件将是一个不错的主意。
这将产生两行用于每个对产品(一行与产品A为p1
和产品B作为p2
,其他与产品B为p1
和产品A为p2
)。 为了防止这种情况发生,改变!=
为任何<
或>
。
而且,在样本数据更密切关注,它可能是你在注册号匹配和日期重叠的几行真的很有趣。 在这种情况下,你可以忽略我对威特灵!=
和<
或>
,取而代之的条件=
毕竟。
SELECT p1.*, p2.*
FROM products p1
JOIN products p2
ON p1.product_reg_no = p2.product_reg_no
AND p1.start < p2.end
AND p2.start < p1.end;
SQL小提琴(未保存的)表明,这种工作原理:
SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end,
p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end
FROM products p1
JOIN products p2
ON p1.product_reg_no = p2.product_reg_no
AND p1.start_date < p2.end_date
AND p2.start_date < p1.end_date
WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date);
WHERE子句消除了被连接到自己的行。 在SELECT列表中的重复的列名淘汰了,你能看到所有数据。 我加了一行:
INSERT INTO products (product_reg_no, start_date, end_date)
VALUES ('AL-NAPT', TO_DATE('08/27/2011', 'MM/DD/YYYY'), TO_DATE('08/30/2011', 'MM/DD/YYYY'));
这是没有选择的 - 证明,它并拒绝不重叠的条目。
如果你想消除双行,那么你必须添加其他花哨的标准:
SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end,
p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end
FROM products p1
JOIN products p2
ON p1.product_reg_no = p2.product_reg_no
AND p1.start_date < p2.end_date
AND p2.start_date < p1.end_date
WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date)
AND (p1.start_date < p2.start_date OR
(p1.start_date = p2.start_date AND p1.end_date < p2.end_date));
这是一个奇怪的查询。 您是否08月14日 - 2001年是27月 - 2001年30月 - 2001年这始终是虚假或8月31日 - 2001年是27月 - 2001年30月 - 2001年也一直是假之间。 所以,你where
条款将永远是假的。
编辑:谢谢你澄清
SQL小提琴演示
select p1.product_reg_no
, p1.start_date p1s
, p1.end_date p1e
, p2.start_date p2s
, p2.end_date p2e
from products p1, products p2
where p1.product_reg_no = p2.product_reg_no
and not ( p1.end_date < p2.start_date
and p1.start_date > p2.end_date );
你想要的是以下情况中(1个代表第一行2第二)
1 1
2 2
1 1
2 2
1 1
2 2
1 1
2 2
1 1
2 2
那你也可以转过身,说你不想要这个:
1 1
2 2
1 1
2 2
我以为你也需要这么做
1 1
2 2
1 1
2 2
在WHERE
子句也可以写不同
not ( p1.end_date < p2.start_date and p1.start_date > p2.end_date )
是相同的
p1.end_date >= p2.start_date or p1.start_date <= p2.end_date
我认为这是所谓德·摩根定律,当我亿万年前曾在学校。
你可能必须考虑,如果你有2级以上的行会发生什么。