I have a sql query to check overlapping of product records in table PRODUCTS. In most cases query works fine except for the following.
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'))
How to make this query to catch all records are overlapping either partially or completely?
If required I can provide table structure with sample records.
Thanks
Update 1
I have added table structure and records here or as below:
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;
The first record which is from August, 14 2012 to August, 31 2012 is overlapping with second record which is from August, 27 2012 to August, 30 2012. So how can I modify my query to get the overlapping?
See Determine whether two date ranges overlap.
You need to evaluate the following, or a minor variant on it using
<=
instead of<
, perhaps:Since you're working with a single table, you need to have a self-join:
The not equal condition ensures that you don't get a record paired with itself (though the
<
conditions also ensure that, but if you used<=
, the not equal condition would be a good idea.This will generate two rows for each pair of products (one row with ProductA as
p1
and ProductB asp2
, the other with ProductB asp1
and ProductA asp2
). To prevent that happening, change the!=
into either<
or>
.And, looking more closely at the sample data, it might be that you're really interesting in rows where the registration numbers match and the dates overlap. In which case, you can ignore my wittering about
!=
and<
or>
and replace the condition with=
after all.SQL Fiddle (unsaved) shows that this works:
The WHERE clause eliminates the rows that are joined to themselves. With the duplicate column names in the SELECT-list eliminated, you get to see all the data. I added a row:
This was not selected — demonstrating that it does reject non-overlapping entries.
If you want to eliminate the double rows, then you have to add another fancy criterion:
This is a strange query. You check if 14-Aug-2001 is between 27-Aug-2001 and 30-Aug-2001 which is always false OR 31-Aug-2001 is between 27-Aug-2001 and 30-Aug-2001 which also always is false. So your
where
clause will always be false.Edit: Thanks for clarification
SQL Fiddle Demo
What you want is the following scenarios (1 stands for the first row 2 for the second)
That you could also be turned around and say you do not want this:
I assumed you also do want this
The
WHERE
clause could also be written differentlyis the same as
I think it was called De Morgan's law when I had that in school eons ago.
You must probably think about what would happen if you have more than 2 rows.