重叠数据

时间:2012-10-01 04:59:43

标签: sql database oracle10g

我有一个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日。那么如何修改我的查询以获得重叠呢?

2 个答案:

答案 0 :(得分:2)

这是一个奇怪的查询。您检查2001年8月14日是2001年8月27日至2001年8月30日之间是否总是错误或2001年8月31日是2001年8月27日至2001年8月30日之间,这也总是错误的。所以你的where子句总是错误的。

修改:感谢您的澄清

SQL Fiddle Demo

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'));