1

I need to write a query to output a table with 2 values - number & description.

Table 1 has 2 columns - id and date

         id        date
         101       04-07-2018
         102       15-11-2018
         103       25-01-2019
         104       28-06-2019

Table 2 has 3 columns - start date, end date and value

         start date    end date     value
         29-11-2016    28-11-2017   A
         29-11-2017    29-11-2018   B
         30-11-2018    15-03-2019   C
         16-03-2019    29-06-2019   D
         30-06-2019    31-11-2021   E

For id 101, 04-07-2018 falls between 29-11-2017 and 29-11-2018, value should be B. For 102, 15-11-2018 falls between 29-11-2017 and 29-11-2018, it starts with B, but later 11/2018 is updated in the next row 30-11-2018 and 15-03-2019, final value should be C instead of B.

I am trying to achieve the final table. Any suggestions would be appreciated.

          id      desc
          101     B
          102     C
          103     C
          104     E
5
  • I don't know what you mean by "updated". ID 102 is clearly within the range for B and NOT within the range for C. Your ranges do not overlap. Commented Oct 18, 2024 at 18:35
  • 1
    November only has 30 days. Not 31 Commented Oct 18, 2024 at 18:41
  • Here is fiddle that might help us fine tune your question and find a solution for you. dbfiddle.uk/RMc1sz7- Commented Oct 18, 2024 at 18:44
  • @TimRoberts: 102 falls within B, but the month & year of 102 is 11 & 2018 which gets updated in third row of table 2. Hence it takes C instead of B Commented Oct 18, 2024 at 18:58
  • 1
    Then what I suggest you do is create new columns in table 2 that round the start and end dates to the beginning of the month, so you don't have to think about this weirdness every time. Commented Oct 18, 2024 at 23:22

2 Answers 2

2

This will find the row with the matching range. I've done this example in sqlite3, so I've rearranged your dates to match the SQL date format.

CREATE TABLE one (
  id integer,
  date date
);

INSERT INTO one VALUES
(         101   ,   '2018-07-04'),
(         102   ,   '2018-11-15'),
(         103   ,   '2019-01-25'),
(         104   ,   '2019-06-28');

CREATE TABLE two (
    start date,
    end date,
    value varchar
);
INSERT INTO two VALUES
(        '2016-11-29',  '2017-11-28',  'A' ),
(        '2017-11-29',  '2018-11-29',  'B' ),
(        '2018-11-30',  '2019-03-15',  'C' ),
(        '2019-03-16',  '2019-06-29',  'D' ),
(        '2019-06-30',  '2021-11-31',  'E' );

SELECT o.id, t.value
FROM one o INNER JOIN two t ON o.date BETWEEN t.start AND t.end;

Output:

101|B
102|B
103|C
104|D

These answers do not match yours, but what you are asking for seems nonsensical. 2019-06-28 is clearly within the range for D, not for E. E doesn't start until two days later.

Followup

Here is sqlite3 code that rounds the start and end dates to the beginning of the month. This produces the results you want, but date functions vary from system to system.

SELECT o.id, t.value
FROM one o INNER JOIN two t ON 
    o.date BETWEEN DATE(t.start,"start of month") AND DATE(t.end, "start of month");

Output:

101|B
102|C
103|C
104|E
Sign up to request clarification or add additional context in comments.

4 Comments

Even though 104's date falls within 16-03-2019 and 29-06-2019, month and year of 104 is 06 and 2019 which are getting updated in last row of table 2. Hence it gets the description of E instead of D.
This would not work @Tim Roberts if the date of id 104 in table one is '2021-11-28'. See the fiddle at dbfiddle.uk/rGkG6tRC .
You should select between the start, and the end of the period. see: dbfiddle.uk/h_p0CK7h
Yes, dates beyond the start of the final month will fail.
1

Making a shift to next row's value ( using Lead() Over() analytic function ) in case of the same year and month of a first table date compared to next row's start date in second table.
Tested with Oracle, Postgres and MariaDB ... may need adjustments for some other sql dialect ...

SELECT  id, val
FROM  ( Select      f.id, 
                    Case When EXTRACT(Year From f.a_date) = EXTRACT(Year From Coalesce(Lead(s.start_date) Over(Order By s.start_date), s.end_date)) And 
                              EXTRACT(Month From f.a_date) = EXTRACT(Month From Coalesce(Lead(s.start_date) Over(Order By s.start_date), s.end_date))
                         Then Coalesce(Lead(s.val) Over(Order By s.start_date), s.val)
                    Else s.val
                    End as val
        From        scnd s
        Left Join   fst f ON( f.a_date Between s.start_date And s.end_date )
      ) a
WHERE       id Is Not Null
ORDER BY    id
ID VAL
101 B
102 C
103 C
104 E

fiddle

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.