Search code examples
sqlsql-serverdaterangedate-range

How to get data between range of dates in SQL Server over 1 year combining 2 tables?


There are 2 tables -

  1. Sales table with details of order_number, item_number and sale_date.
  2. Promotions table with details of item_number, promotion_start_date and promotion_end_date.

Promotions run all through the year over a range of days. Need is to extract list of items sold when no promotion was running.

Need to extract only the order numbers between

  • "first promotion_end_date" and "second promotion_start_date" then
  • "second promotion_end_date" and "third promotion_start_date" then
  • "third promotion_end_date" and "fourth promotion_start_date" and so on.

Sample tables are as follows -

1) Promotions table : ( When promotion_end_date is 'Null', promotion is still 'ACTIVE')

item_number promotion_start_date promotion_end_date
ABC0001 12-31-2020 01-19-2021
ABC0001 03-01-2021 03-31-2021
ABC0005 02-05-2021 03-01-2021
ABC0002 06-01-2021 07-31-2021
ABC0001 09-31-2021 11-05-2021
ABC0001 11-08-2021 Nil

2) Sales Table :

order_number item_number sale_date
110000011 ABC0001 01-18-2021
110000012 ABC0001 01-31-2021
110000013 ABC0002 06-30-2021
110000014 ABC0001 07-31-2021
110000015 ABC0005 04-05-2021
110000016 ABC0001 10-05-2021
110000017 ABC0001 12-01-2021
110000018 ABC0002 08-30-2021
110000019 ABC0001 04-01-2021
110000020 ABC0001 07-30-2021
110000021 ABC0005 02-28-2021
110000022 ABC0001 11-06-2021

3) Expected Result :

order_number item_number sale_date
110000012 ABC0001 01-31-2021
110000014 ABC0001 07-31-2021
110000015 ABC0005 04-05-2021
110000017 ABC0001 12-01-2021
110000018 ABC0002 08-30-2021
110000019 ABC0001 04-01-2021
110000020 ABC0001 07-30-2021
110000022 ABC0001 11-06-2021

Solution

  • There are many ways to solve this kind of problem but I generally prefer NOT EXISTS:

    SELECT order_number, item_number, sale_date
    FROM dbo.Sales AS s
    WHERE NOT EXISTS 
    (
      SELECT 1 
        FROM dbo.Promotions AS p
        WHERE s.item_number = p.item_number
        AND s.sale_date >= p.promotion_start_date
        AND s.sale_date <= COALESCE(p.promotion_end_date, GETDATE())
    );
    

    I think the trickiest part here is substituting the end date with a valid point in time when the promotion is ongoing.

    • Example db<>fiddle which shows how we love to see table structure and sample data and also corrects September 31st.