Joining on optional - sql

I have 2 tables:
Table1 - Criteria
Office_ID Bus_Stream Bus_Criteria Crit_Value
1 ABC 0 20
1 ABC 1 21
1 ABC 2 7
2 ABC 0 15
2 ABC 1 12
2 ABC 2 21
3 XYZ 1 17
3 XYZ 2 3
Table2 - Limit
Bus_Stream GroupID TypeID SubgroupID Bus_Limit
ABC 20 21 7 50
ABC 15 12 21 100
XYZ 99 17 3 120
I need to create a join that allows me to pull back:
Result
Bus_Stream Office_ID GroupID TypeID SubgroupID Bus_Limit
ABC 1 20 21 7 50
ABC 2 15 12 21 100
XYZ 3 (null) 17 3 120
Essentially, I need to join Table1.Crit_Value based on the following:
Table1.Bus_Criteria Table2
0 GroupID
1 TypeID
2 SubGroupID
with the added complication that if one or two of the 0/1/2 values from Bus_Criteria is missing, the joins will still occur on the remaining criteria.
I have tried a number of combinations of AND/OR on the join to no avail.
Any ideas folks?

This may be what you're after.. use a case statement on the join.
The problem here is your data in t2 isn't normalized, you could also unpivot the 3 data columns in t2 so the join is more natural.
SELECT T2.Bus_Stream, T1.Office_ID, T2.GroupID, T2.TypeID, T2.SubGroupId, T2.bus_Limit
FROM T1
INNER JOIN T2
on T1.Bus_Stream = T2.Bus_Stream
and T1.Crit_value = case when T1.Bus_Critiera = 0 then T2.GroupID
when T1.Bus_Critiera = 1 then T2.TypeID
when T1.Bus_Critiera = 2 then T2.SubGroupID
end

Did you try something like this?
SELECT
t1.*, t2.*
FROM Table1 t1
INNER JOIN Table2 t2 ON
t1.Bus_Stream = t2.Bus_Stream AND
CASE
WHEN t1.Bus_Criteria = 0
THEN t2.GroupID = t1.Crit_Value
WHEN t1.Bus_Criteria = 1
THEN t2.TypeID = t1.Crit_Value
ELSE
t2.SubGroupID = t1.Crit_Value
END

Related

SQL Server : multiple rows single line

I would like to get the representation of one record based on the primary key value from multiple tables. As shown below, each table can have multiple values based on this primary key value.
TABLE-1
ID
NAME
1
AA
2
BB
3
CC
4
DD
5
EE
TABLE-2
ID
SCHOOL
AUT
1
11
A
2
11
A
2
12
B
3
11
A
4
12
A
4
13
B
5
13
A
TABLE-3
ID
TC
1
101
2
102
2
103
2
104
3
105
4
106
4
107
5
108
The result below is the value obtained with an OUTER JOIN.
SELECT
T1.ID, T2.SCHOOL, T3.TC, T2.AUT
FROM
T1
LEFT OUTER JOIN
T2 ON T1.ID = T2.ID
LEFT OUTER JOIN
T3 ON T1.ID = T3.ID
ORDER BY
T1.ID ASC
ID
SCHOOL
TC
AUT
1
11
101
A
2
11
102
A
2
12
102
B
2
11
103
A
2
12
103
B
2
11
104
A
2
12
104
B
3
11
105
A
4
12
106
A
4
13
106
B
4
12
107
A
4
13
107
B
5
13
106
A
How can I get the result like below?
ID
SCHOOL
TC1
TC2
TC3
1
11
101
2
11
102
103
104
3
11
105
4
12
106
107
5
13
108
The important thing here is that in the result value, SCHOOL only shows that AUT is 'A'.
I would appreciate it if you let me know your query.
It looks, from your desired results, you just need to use row_number in combination with a conditional aggregate. Your sample data seems a little inadequate, I can't see any requirement for table1 at all.
Try the following:
with t as (
select t2.id,t2.school,t3.tc, Row_Number() over(partition by t2.id order by t3.tc) col
from t2 join t3 on t2.id=t3.id
where aut='A'
)
select id,school,
max(case when col=1 then tc end) TC1,
max(case when col=2 then tc end) TC2,
max(case when col=3 then tc end) TC3
from t
group by id, school
Example SQL Fiddle
SELECT
T1.ID, T2.SCHOOL,
GROUP_CONCAT(T3.TC),
GROUP_CONCAT(T2.AUT)
FROM
T1
LEFT OUTER JOIN
T2 ON T1.ID = T2.ID
LEFT OUTER JOIN
T3 ON T1.ID = T3.ID
GROUP BY
T1.ID, T2.SCHOOL
WHERE
T2.AUT = ‘A’
ORDER BY
T1.ID ASC
Notice that GROUP_CONCAT concatenates the values in the row.
EDIT: oh my, haven't seen that it's a SQL Server question!
Just replace GROUP_CONCAT with STRING_AGG if you’re using SQL Server 2017 or newer.

Join two tables, using value from the first unless it is null, otherwise use value from the second

I have three tables which look like those:
TABLE 1
id j_id
1 1
2 2
3 3
TABLE 2
id j_id table1_id
1 57 1
2 84 1
3 1 1
4 9 2
5 2 2
and every j has a value in a third table
id value
1 1abc
2 2bcd
3 3abc
57 57abc
84 84abc
9 9abc
I am trying to write a query which will join table 1 and table 2 and use the J value from the third table instead of the j_id, but the problem is that I want to use the j value from the second table if it exists and otherwise use the value from the first table.
in order the make it clearer this is my query result without using the third table:
tbl1.j_id tbl2.j_id
1 1
1 84
1 57
2 2
2 9
3 null
I want the end query result to use the second table's j value unless it is null:
tbl1.j_id tbl2.j_id j_id
1 1 1abc
1 84 84abc
1 57 57abc
2 2 2abc
2 9 9abc
3 null 3abc
(Question and title edits are more than welcome, weren't that sure how to phrase them..)
You can simply JOIN to table3 on the COALESCE of table2.j_id and table1.j_id:
SELECT t1.j_id AS t1_j_id, t2.j_id AS t2_j_id, t3.value
FROM table1 t1
LEFT JOIN table2 t2 ON t2.table1_id = t1.id
JOIN table3 t3 ON t3.id = COALESCE(t2.j_id, t1.j_id)
Output:
t1_j_id t2_j_id value
1 1 1abc
1 57 57abc
1 84 84abc
2 2 2bcd
2 9 9abc
3 null 3abc
Demo on dbfiddle
One solution is to left join table3 twice:
select
t1.j_id,
t2.j_id,
coalesce(t31.value, t32.value) j_value
from
table1 t1
left join table2 t2 on t2.table1_id = t1.id
left join table3 t31 on t31.id = t2.j_id
left join table3 t32 on t32.id = t1.j_id

SQL Server 2012 Update table rate based on rate in table 2

I have two tables and below is the example
Table1
KEY BEGIN_DATE TOTAL_RATE
1 1974-01-01 3
1 1981-01-01 3
1 1983-01-01 4
1 1985-07-01 4
1 1989-10-01 7
1 1990-07-01 10
1 1997-10-01 11
1 2008-04-01 13
TABLE2
KEY END_DATE RATE_REDUCED
1 1989-09-30 2
1 1997-09-31 4
From Table 2 if key matches then we need to reduce TOTALRATE from Table 1
with RATEREDUCED in Table 2 where BEGINDATE > ENDDATE and it should happen
till the end of table 2 ENDDATE
EXPECTED RESULTS/UPDATE TO TABLE 1:
RESULT
KEY BEGIN_DATE NEW_RATE
1 1974-01-01 3
1 1981-01-01 3
1 1983-01-01 4
1 1985-07-01 4
1 1989-10-01 7 - 2 = 5 (Date is Greater than 1989-09-30)
1 1990-07-01 10 - 2 = 8 (Date is Greater than 1989-09-30)
1 1997-10-01 11 - 2 - 4 = 5 (Date is Greater than two dates)
1 2008-04-01 13 - 2 - 4 = 7 (Date is Greater than two dates)
I have many keys in table two and table one.
Is update with join possible
Thanks in advance
Similar to Gordon's, here we use use an Update in a CROSS APPLY. This approach will only update the records which match the criteria
Update Table1 Set TOTAL_RATE=TOTAL_Rate-B.Adj
From Table1 A
Cross Apply (
Select Adj=sum(RATE_REDUCED)
From Table2
Where END_DATE<=A.BEGIN_DATE and [Key]=A.[Key]
) B
Where B.Adj is not NULL
The Updated Table1 Looks like this now
KEY BEGIN_DATE TOTAL_RATE
1 1974-01-01 3
1 1981-01-01 3
1 1983-01-01 4
1 1985-07-01 4
1 1989-10-01 5
1 1990-07-01 8
1 1997-10-01 5
1 2008-04-01 7
This looks like a good application of outer apply:
select t1.*,
(t1.total_rate - coalesce(t2.rate_reduced, 0)) as total_rate
from table1 t1 outer apply
(select sum(t2.rate_reduced) as rate_reduced
from table2 t2
where t1.begin_date > t2.end_date and
t1.key = t2.key
) t2;
EDIT:
If you want to turn this into an update, that is easy:
update t1
set total_rate = (t1.total_rate - coalesce(t2.rate_reduced, 0))
from table1 t1 outer apply
(select sum(t2.rate_reduced) as rate_reduced
from table2 t2
where t1.begin_date > t2.end_date and
t1.key = t2.key
) t2;
I'm not sure about the difference in performance between using a join or using a subquery. Maybe you can try out the solutions mentioned in the other answers and compare it to a (simpler?) subquery approach:
update table1
set total_rate = total_rate -
(select COALESCE(sum(new_rate),0)
from table2
where begin_date > end_date
and table1.key = table2.key)

How to Join two table using where and sum statement

Dear All I have below two table
Table1
RecdId RecdNo
1 A/1
2 A/2
3 A/3
Table2
RecdId RecdAmt1 RecdAmt2 RecdAmt3
1 100 10 5
1 150 20 10
1 200 30 15
2 500 5 50
2 400 10 60
3 100 5
I want solution that how to join above two table with sum of Table1.RecdId = Tabble2.RecdId
Below result I require
RecdId RecdNo TotRecdAmt1 TotRecdAmt2 TotRecdAmt3
1 A/1 450 60 30
2 A/2 900 15 110
3 A/3 100 5
Thanking You,
You can inner join two tables and use a group by clause to calculate sum for each combination of RecdId and RecdNo:
select t1.RecdId
, t1.RecdNo
, sum(t2.RecdAmt1) as TotRecdAmt1
, sum(t2.RecdAmt2) as TotRecdAmt2
, sum(t2.RecdAmt3) as TotRecdAmt3
from tbl1 t1
join tbl2 t2 on t1.RecdId = t2.RecdId
group by t1.RecdId
, t1.RecdNo
SQLFiddle
SELECT T1.RECDID, T1.RECDNO, TotRecdAmt1, TotRecdAmt2, TotRecdAmt3
FROM TABLE1 T1, (SELECT RECdID, SUM(RecdAmt1) TotRecdAmt1, SUM(RecdAmt2) TotRecdAmt2,
SUM(RecdAmt3) TotRecdAmt3 FROM TABLE2 GROUP BY RECdID) T2
WHERE T1.RECdID = T2.RECDID;
SELECT Table1.RecdId,RecdNo,SUM(RecdAmt1) AS TotRecdAmt1,
SUM(RecdAmt2) AS TotRecdAmt2,
SUM(RecdAmt3) AS TotRecdAmt3
FROM Table1,Table2
WHERE Table1.RecdId=Table2.RecdId
GROUP BY Table1.RecdId,RecdNo

Proc Sql - Same column name from 3 tables and manipulate

Here is the example data.
Table1:
iD Flag Reason
1 1 ABCD
2 0
3 0
4 1 ERS
5 0
Table2:
iD Flag Reason
1 1 ERS
2 1 FGH
3 1 DDD
4 1
5 0
Table3:
iD Flag Reason
1 1
2 1 DDD
3 1
4 1
5 1 ERS
I am trying to write a proc sql that will help me separate the different reason case scenario.
proc sql;
select case when (table1.flag = 1 and reason = 'ABCD') then 1
when (table2.flag = 1 and reason = 'ABCD') then 1
when (table3.flag = 1 and reason = 'ABCD') then 1
when (table1.flag = 1 and reason = 'FGH') then 2
when (table2.flag = 1 and reason = 'FGH') then 2
:
:
when (table3.flag = 1 and reason = 'ERS') then 4
Else 0
End as output
from table1
inner join table2 on table1.id = table2.id
inner join table3 on table1.id = table3.id
;
Here is the output I am trying to get,
Id Reason Output
1 ABCD 1
2 FGH 2
3 DDD 3
4 ERS 4
5 ERS 4
Even though, the reason might change in different tables for the same id, i need the first occurring reason in any of the table based on the Flag variable and assign the output.
Is there any other way to do the same?
Thanks in advance.
The following query produces the output that you are looking for:
select t1.id,
(case when t1.flag = 1 then t1.reason
when t2.flag = 1 then t2.reason
when t3.flag = 1 then t3.reason
end) as reason,
(case when calculated reason = 'ABCD' then 1
when calculated reason = 'FGH' then 2
when calculated reason = 'DDD' then 3
when calculated reason = 'FGH' then 4
else 0
end) as output
from table1 t1 inner join
table2 t2
on t1.id = t2.id inner join
table3 t3
on t1.id = t3.id;
Note the use of the calculated keyword. This is a nice feature in proc sql that makes it unnecessary to use a subquery or repeated the defining expression.