Home > Enterprise >  How to check for overlapping datetimes with nullable data?
How to check for overlapping datetimes with nullable data?

Time:10-14

All other questions and queries on this topic seem to be assuming all or some of the datetimes involved are non-null. I haven't seen a solution for when all of the datetimes are possibly NULL.

In my use-case, I have promotions for products which have a start and end date.

  • A start date of NULL means the promotion is always active, as long as the end date hasn't passed.
  • An end date of NULL means the promotion lasts forever, and is active assuming the start date has passed.
  • A promotion with both NULL means the promotion is always active and will overlap with every other promotion possible for that product.

I want to give the client a warning when they try to add another promotion for a product that overlaps with an existing promotion.

So, we have four datetime2, StartA, EndA and StartB, EndB, where none, some or all of these may be NULL.

How can I write a SELECT statement that returns all promotions which overlap?

If relevant I'm using SQL Server, and here is a SQLFiddle if it helps.

CodePudding user response:

I'm going to assume the following:

  • "Returns all promotions which overlap" = "Returns all promotions which are active"
  • Table is called "promotions".
  • Relative columns on the table are "StartDate" and "EndDate"

With those in mind, it's relatively simple:

SELECT * FROM promotions
WHERE
( StartDate IS NULL AND EndDate<=GETDATE() ) OR  -- A start date of NULL means the promotion is always active, as long as the end date hasn't passed
( EndDate IS NULL And StartDate>=GETDATE() ) OR -- An end date of NULL means the promotion lasts forever, and is active assuming the start date has passed.
( StartDate IS NULL AND EndDate IS NULL ) -- A promotion with both NULL means the promotion is always active 

CodePudding user response:

This can be achieved using self join as shown below.

Note : This will be a little costly for a very huge table.

---Creating table
---PromotionID is Unique. productID is product for which promotion is created    

create table product_promotion(promotion_id int, product_id int, startdate datetime, EndDate datetime)

--Inserting Sample Data
--For product id 101 and 102 there are overlapping promotions based on the condition described in quetion

Insert into product_promotion
values(1,101,'2022-10-01','2022-10-10'),
(2,101,'2022-10-11',null),
(3,101,null,'2022-11-30'),
(4,102,null,null),
(5,102,'2022-11-01',null),
(6,103,'2022-11-01','2022-11-10'),
(7,103,'2022-11-11','2022-11-15')

--Query to find overlapping results.

select a.product_id,a.promotion_id ,b.promotion_id Overlapped_PromotionId,  
a.startdate, a.EndDate,
 b.startdate Overlapped_StartDate, a.EndDate Overlapped_EndDate
from product_promotion a
join product_promotion b on a.product_id = b.product_id and a.promotion_id != b.promotion_id
where (a.startdate is null and a.EndDate is null)
or (a.startdate is null and b.startdate < a.EndDate) 
or (a.EndDate is null and b.EndDate > a.EndDate)

--Query Results

product_id  promotion_id Overlapped_PromotionId startdate               EndDate                 Overlapped_StartDate    Overlapped_EndDate
----------- ------------ ---------------------- ----------------------- ----------------------- ----------------------- -----------------------
101         3            1                      NULL                    2022-11-30 00:00:00.000 2022-10-01 00:00:00.000 2022-11-30 00:00:00.000
101         3            2                      NULL                    2022-11-30 00:00:00.000 2022-10-11 00:00:00.000 2022-11-30 00:00:00.000
102         4            5                      NULL                    NULL                    2022-11-01 00:00:00.000 NULL

(3 rows affected)
  • Related