我有一个SQL查询来检查表PRODUCTS中产品记录的重叠。 在大多数情况下,查询工作正常,但以下情况除外。
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
我添加了表格结构和记录here或如下:
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;
第一张记录是 2012年8月14日至 2012年8月31日重叠 第二条记录来自 2012年8月27日至 2012年8月30日。那么如何修改我的查询以获得重叠呢?
答案 0 :(得分:2)
这是一个奇怪的查询。您检查2001年8月14日是2001年8月27日至2001年8月30日之间是否总是错误或2001年8月31日是2001年8月27日至2001年8月30日之间,这也总是错误的。所以你的where
子句总是错误的。
修改:感谢您的澄清
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代表第二行的第一行)
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
我认为,当我在学校学习之前,它被称为De Morgan定律。
你必须考虑如果你有两行以上会发生什么。
答案 1 :(得分:2)
请参阅Determine whether two date ranges overlap。
您需要使用<=
代替<
评估以下内容或其中的次要变体,或许:
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;
不等的条件可确保您不会获得与自身配对的记录(尽管<
条件也可以确保,但如果您使用<=
,则不等的条件将是一个好的想法。
这将为每对产品生成两行(一行,ProductA为p1
,ProductB为p2
,另一行为ProductB为p1
,ProductA为{{1} })。为防止发生这种情况,请将p2
更改为!=
或<
。
而且,仔细观察样本数据,可能是您在注册号匹配且日期重叠的行中非常有趣。在这种情况下,您可以忽略我对>
和!=
或<
的疑虑,并将条件替换为>
。
=
SQL Fiddle(未保存)显示这有效:
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;
WHERE子句消除了连接到它们自己的行。删除SELECT列表中的重复列名称后,您将看到所有数据。我添加了一行:
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);
未选中此项 - 证明它拒绝不重叠的条目。
如果要消除双行,则必须添加另一个花哨的标准:
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'));