Left outer Table Joins on multiple conditions. - sql

I have two tables and want to left outer join.
First Table
Id RenewalTerm EffectiveDt RenewalDt
400001 -1 8/1/2012 8/1/2013
400001 0 8/1/2013 8/1/2014
400001 1 8/1/2014 8/1/2015
400001 2 8/1/2015 8/1/2016
400001 3 8/1/2016 8/1/2017
400001 4 8/1/2017 8/1/2018
SecondTable
Id RenewalTerm MaxSize AY DateTime EffectiveDt RenewalDt
400001 -1 2 2013 2/25/2013 8/1/2012 8/1/2013
400001 -1 1.75 2013 2/25/2013 8/1/2012 8/1/2013
400001 2 1.75 2016 5/1/2016 8/1/2015 8/1/2016
Expected Table
Result
Id RenewalTerm EffectiveDt RenewalDt DateTime AY MaxSize
400001 -1 8/1/2012 8/1/2013 *2/25/2013 2013 2*
*400001 -1 8/1/2012 8/1/2013 2/25/2013 2013 1.75*
400001 0 8/1/2013 8/1/2014 NULL NULL NULL
400001 1 8/1/2014 8/1/2015 NULL NULL NULL
*400001 2 8/1/2015 8/1/2016 5/1/2016 2016 1.75*
400001 3 8/1/2016 8/1/2017 NULL NULL NULL
400001 4 8/1/2017 8/1/2018 NULL NULL NULL
In second table, renewal term -1 is repeating and in first table theres just one -1. So, one of the -1 should get updated with Maxsize, AY and datetime and a new row of -1 from second table should be added to first table.
In second table, renewal term 2 is just once. So the extra columns Maxsize, AY and datetime from second table should get added to first.
I have been trying to solve this for a long time. Can somebody please help me with this. Thank you.
I have added italic/stars to show which data got updated/added

Basic Left Join theory
COALESCE function
SELECT a.ID, a.RenewalTerm, COALESCE( b.EffectiveDt, a.EffectiveDt ) AS EffectiveDt,
COALESCE( b.RenewalDt, a.RenewalDt ) AS RenewalDt,
MaxSize, AY, [DateTime]
FROM [FristTable] AS a
LEFT JOIN [SecondTable] AS b ON a.ID = b.ID AND a.RenewalTerm = b.RenewalTerm

It looks like a simple left join + coalesce resolve your problem.
Please check this fiddle:
Select
t1.Id,
t1.RenewalTerm,
coalesce(t2.EffectiveDt, t1.EffectiveDt) EffectiveDt,
coalesce(t2.RenewalDt, t1.RenewalDt) RenewalDt,
t2.DateTime,
t2.AY,
t2.MaxSize
From
table1 t1
left join table2 t2 on t1.id = t2.id and t1.RenewalTerm = t2.RenewalTerm

I see this as:
select t1.*, t2.DateTime, t2.AY, t2.MaxSize
from table1 t1 left join
table2 t2
on t1.id = t2.id and t1.renewalterm = t2.renewalterm;
Perhaps I'm missing something, but I see no need for coalesce().

Related

How do I join a table but filter only that table prior to join and do the same for the other table?

Apologies for the poor formatting (this is my first post.)
I'm working this on Snowflake - SQL (without writing permissions, so I can't alter the data.)
I want to make a report that will capture monthly fees on one table.
Table 2 will always have matching ID's but occasionally the tables 1,3,4 will not have matching ID's with each other.
In this case:
I want the fees of a certain month "202301" to be on the same table, joining them based on the ID.
TABLE 1,2,4 will join with no issue but the TABLE3 has no matches. How can I filter the bill_month of each table to only include "202301" without impacting the join in the way it currently is?
We have TABLE1 has
ID
Billing_month
A_FEE
MCC
1
202301
20.00
0001
1
202212
34.00
0001
2
202301
51.00
2222
2
202211
22.00
2222
2
202210
51.00
2222
3
202109
22.00
3333
3
202301
22.00
3333
We have TABLE2
ACCT
Rate_Program
1
IC
2
IC
3
IC
4
IC
5
SFNF
We have TABLE3
ID
Billing_month
B_FEE
MCC
4
202301
10.00
1111
4
202212
24.00
1111
2
202201
21.00
2222
2
202211
42.00
2222
2
202210
21.00
2222
3
202109
32.00
3333
3
202201
42.00
3333
We have TABLE4: A unique fee
ID
Billing_month
C_FEE
MCC
1
202301
15.00
0001
1
202212
34.00
0001
2
202301
51.00
2222
2
202211
22.00
2222
2
202210
54.00
2222
3
202109
22.00
3333
3
202301
24.00
3333
I would prefer to not use a NOT statement as there are too many billing_month values to add. And I thought by including the conditional clause of billing_month = '202301' would allow me to get my wanted output but I was wrong. I'm fairly new to SQL so hopefully some input would help! Thanks.
SELECT * FROM TABLE1 t1
LEFT JOIN TABLE2 t2
ON t1.ID = t2.acct and t1.billing_month = '202301'
FULL JOIN TABLE3 t3
ON t3.ID, = t2.acct and t3.billing_month = '202301'
FULL JOIN TABLE4 t4
ON t4.ID, = t2.acct and t4.billing_month = '202301'
where t1.MCC not in ('4444','5555')
and t2.rate_program not in ('SFNF', 'SPSF', 'SF')
Real Output
ID
Billing_month
A_FEE
B_FEE
C_FEE
MCC
Rate_Program
1
202301
20.00
15.00
0001
IC
2
202301
51.00
54.00
2222
IC
3
202301
22.00
24.00
3333
IC
Wanted Output
ID
Billing_month
A_FEE
B_FEE
C_FEE
MCC
Rate_Program
1
202301
20.00
15.00
0001
IC
2
202301
51.00
54.00
2222
IC
3
202301
22.00
24.00
3333
IC
4
202301
10.00
1111
IC
SELECT * FROM TABLE1 t1 LEFT JOIN TABLE2 t2
ON t1.ID = t2.acct and t1.billing_month = '202301' FULL JOIN TABLE3 t3
ON t3.ID = t2.acct and t3.billing_month = '202301'FULL JOIN TABLE4 t4
ON t4.ID = t2.acct and t4.billing_month = '202301'
where (t1.MCC is null or t1.MCC not in ('4444','5555'))
and (t2.rate_program is null or t2.rate_program not in ('SFNF', 'SPSF', 'SF') )
and (t1.billing_month is null or t1.billing_month like '202301')
and (t3.billing_month is null or t3.billing_month like '202301')
and (t4.billing_month is null or t4.billing_month like '202301')
This seems to have worked (expanding on what #Uma Deivasigamani suggested.)
The issue that I currently am running into is this now
ID
Billing_month
A_FEE
B_FEE
C_FEE
MCC
Rate_Program
1
202301
20.00
15.00
0001
IC
2
202301
51.00
54.00
2222
IC
3
202301
22.00
24.00
3333
IC
10.00
We get the fee but the Joined ID column is returning null even though there is a match.
The 4th row is missing in your query output because of possibility of null value in t1.MCC, t2.rate_program columns.
So you would have to add an additional condition to check for NULL values before checking the not in condition:
SELECT * FROM TABLE1 t1
LEFT JOIN TABLE2 t2
ON t1.ID = t2.acct and t1.billing_month = '202301'
FULL JOIN TABLE3 t3
ON t3.ID = t2.acct and t3.billing_month = '202301'
FULL JOIN TABLE4 t4
ON t4.ID = t2.acct and t4.billing_month = '202301'
where (t1.MCC is null or t1.MCC not in ('4444','5555'))
and (t2.rate_program is null or t2.rate_program not in ('SFNF', 'SPSF', 'SF') )
;
while combining the ID columns in the select clause of the query, you can use like below:
SELECT IFNULL(t1.id,IFNULL(t2.acct,IFNULL(t3.id,t4.id)))

SQL get count(*) before several dates

It sounds so simple but I can't figure it out. I have 2 tables:
TABLE 1 contains a list of projects with the dates at which they were approved.
PROJECT
APPROVAL_DATE
A
12/06/2019
A
01/09/2020
A
05/08/2021
A
07/12/2021
B
01/05/2018
B
06/09/2019
B
12/23/2020
TABLE 2 contains dates when tests were performed on these projects.
PROJECT
TEST_DATE
A
01/06/2019
A
01/07/2019
A
02/21/2019
...
...
A
06/22/2021
...
...
B
01/12/2021
...
...
THIS IS WHAT I NEED: For each project, I want to count the total number of tests prior to each APPROVAL_DATE, so I would have this:
PROJECT
APPROVAL_DATE
TOTAL_TESTS_BEFORE_APPROVAL_DATE
A
12/06/2019
1264
A
01/09/2020
1568
A
05/08/2021
1826
A
07/12/2021
2209
B
01/05/2018
560
B
06/09/2019
790
B
12/23/2020
1560
here is how you can do it using left join :
select t1.project, t1.APPROVAL_DATE, count(t2.test_date) TOTAL_TESTS_BEFORE_APPROVAL_DATE
from table1 t1
left join table2 t2
on t1.project = t2.project
and t1.APPROVAL_DATE > t2.TEST_DATE
group by t1.project, t1.APPROVAL_DATE

Selecting row corresponding to date range in an inner join

I have data in one table (Table A) that looks like:
id datestart dateend department
1 2008-01-01 9999-12-31 fmcg
2 2010-02-01 2011-04-09 sales
. . . .
. . . .
With millions of rows and 9999-12-31 means current date. I have another table (Table B) that looks like:
yearmonth id
2010-01-01 1
2010-01-01 2
2010-02-01 1
2010-02-01 2
. .
. .
id in Table A can have multiple rows, for instance, id 2 was in sales but there is another row that looks like:
id datestart dateend department
2 2011-04-10 9999-12-31 fmcg
Which means they moved to fmcg after sales (no overlap of dates)
What I'm trying to do is add another column in Table B which shows where the employee was working at yearmonth:
yearmonth id department
2010-01-01 1 fmcg
2010-01-01 2 NULL
2010-02-01 1 fmcg
2010-02-01 2 sales
. .
. .
2011-05-01 1 fmcg
2015-05-01 2 fmcg
Apologies I am unable to post the exact code I've used as it's on my work computer and I'm currently using a different computer but it looks similar to:
select a.*
, case when b.dateend = '9999-12-31' then b.department
when a.yearmonth < b.dateend then b.department else b.department end as department
from table_a a
inner join table_b b on a.id = b.id
(apologies if missing crucial bits, am going by memory)
I know this code doesn't work as I get something similar to:
yearmonth id department
2010-01-01 1 fmcg
2010-01-01 2 NULL
2010-02-01 1 fmcg
2010-02-01 2 sales
2010-02-01 2 fmcg
. .
. .
2011-05-01 1 fmcg
2015-05-01 2 fmcg
2015-05-01 2 sales
but I'm having troubles understanding what will work. If you could help me out, I would greatly appreciate it!
Try this:
SELECT B.ID, B.YearMonth, ApplyResult.Department FROM TableB B
OUTER APPLY(
SELECT A.Department FROM TableA A
WHERE A.ID = B.ID AND B.YearMonth BETWEEN A.DateStart AND A.DateEnd
) ApplyResult
Or this:
SELECT B.ID, B.YearMonth, A.Department FROM TableB B
LEFT OUTER JOIN TableA A On A.ID = B.ID AND B.YearMonth BETWEEN A.DateStart AND A.DateEnd
TableA:
ID DateStart DateEnd Department
1 2008-01-01 9999-12-31 DepA
2 2010-02-01 2010-03-09 DepA
2 2010-03-10 9999-12-31 DepB
TableB:
ID YearMonth
1 2010-01-01
2 2010-01-01
1 2010-02-01
2 2010-02-01
1 2010-03-01
2 2010-03-01
1 2010-04-01
2 2010-04-01
Output:
ID YearMonth Department
1 2010-01-01 DepA
2 2010-01-01 NULL
1 2010-02-01 DepA
2 2010-02-01 DepA
1 2010-03-01 DepA
2 2010-03-01 DepA
1 2010-04-01 DepA
2 2010-04-01 DepB
Just add the date condition to the on clause:
select a.*, b.department
from table_a a inner join
table_b b
on a.id = b.id and
b.yearmonth between a.datestart and a.dateend

How to join a table to another one depending two date columns?

I have two tables which are
T1:
UserID Tier BeginDate EndDate
8278020 1 2019-03-02 18:33:04.893 2019-03-28 10:34:33.837
8278020 2 2019-03-28 10:34:33.837 2019-04-01 16:48:22.107
8278020 3 2019-04-01 16:48:22.107 2019-04-07 21:44:40.060
8278020 4 2019-04-07 21:44:40.060 2019-06-30 23:59:59.999
T2:
UserID GiftCardID UseDate OrderID IsUsed
8278020 165491838 2019-03-06 23057796 1
8278020 165491839 2019-03-10 23106429 1
8278020 165491840 2019-03-24 23277217 1
8278020 166418161 NULL NULL 0
8278020 166418162 NULL NULL 0
8278020 167026357 2019-04-22 23594414 1
8278020 167026358 2019-04-28 23668492 1
I want to match two tables such that I show the each tier of the customer when he/she used the giftcard.
For example, when the user used the Giftcard with '165491839' he was in tier 1.
Or at GiftCardID = '167026357' the tier is 4.
I couldn't find how to match the tables according to that.
I wait for your help...
Just use JOIN:
select t2.*, t1.tier
from table2 t2 left join
table1 t1
on t2.userid = t1.userid and
t2.usedate >= t1.begindate and
t2.userdate < t1.enddate;
This is a left join, so you won't lose rows if, for some reason, the dates don't match.

what is the best method to Identify which pairs of rows have identical Products, Customers and Measures, and overlapping date ranges?

image of sample question where i have to identify duplicate rows then make date ranges not overlap.
The overlapping for row 1, 2 is represented as:
rows 1 and 2 are overlap , like this:
20130101 |--------------------| 20130401
20130301 |----------------------| 20131231
You can use T-Sql language in MS SQL Server:
select t1a.id , t1.id second_id,
t1.valid_from_day , t1.valid_to_day ,
t1a.valid_from_day second_valid_from_day ,
t1a.valid_to_day second_valid_to_day
from t1 t1a
cross apply
(
select * from t1
where t1.product = t1a.product
and t1.customer = t1a.customer
and t1.measure = t1a.measure
and t1.id <> t1a.id
and t1.valid_from_day >= t1a.valid_from_day -- overlap
and t1.valid_to_day >= t1a.valid_to_day
) t1
The results of the query is:
id second_id valid_from_day valid_to_day second_valid_from_day second_valid_to_day
1 2 2013-03-01 2013-12-31 2013-01-01 2013-04-01
4 5 2013-03-01 2014-04-01 2013-01-01 2013-04-01
9 10 2014-04-01 2015-01-01 2013-03-01 2013-12-31
so The pairs identical are:
pair 1,2
pair 4,5
pair 9,10