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
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)))
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
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
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.
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