Proc Sql - Same column name from 3 tables and manipulate - sql

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.

Related

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

Joining on optional

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

Compare multiple Rows Based on another table

Lets say I have following tables:
Table1
ID Number
1 2
2 34
3 1 <---- Input (ID = 3) ==> (Number = 1)
4 6
5 5
*6* 7 <---- Want to find (Number = 6) because match in Table2
7 22
and Table2
Number Code Att1 Att2 Att3
1 1 1 <-----|
1 2 1 2 <-----|
6 2 f 2 |
6 3 4 3 2 |
2 4 6 |---Match
22 5 2 2 2 |
5 2 h 3 b |
7 1 1 <-----|
7 2 1 2 <-----|
7 h 5 r
So here is my Problem:
I want the IDs from Table1 that have all Code and Attributes from Table2 that a given (variable) input ID has. At the end I want to create a stored procedure/function that gives me all IDs meeting that condition.
As an Example:
Input-ID: 3. Would return ID 6 because Number 7 (mapped from ID 6 in Table1) has the rows Number 1 (mapped from ID 3 in Table1) has. It has more but that doesn't matter, its just important it has all rows the input one has.
(I can't find a solution to comparing a set of rows to another set of rows that is not known before.)
Thanks for any help!
Edit:
To make it more understandible, here what I want in words step-by-step.
Map input ID to Number in Table1
Get All Rows from Table2 having Number from Step 1
Get all Number that have the same (can have more) Rows as from Step 2
Get IDs for that Numbers (and return them)
Try something like this. Haven't tested it, but basically you inner join on all of the attributes that need to match. The HAVING clause is a crude check to make sure that it matched all the rows. Edit: Forgot to add the input ID WHERE clause.
SELECT t1b.ID FROM
Table1 t1a
INNER JOIN Table2 t2a ON t1a.Number = t2a.Number
INNER JOIN Table2 t2b ON t2a.Number <> t2b.Number AND t2a.Code = t2b.CODE AND t2a.Att1 = t2b.Att1 AND t2a.Att2 = t2b.Att2 AND t2a.Att3 = t2b.Att3
INNER JOIN Table1 t1b ON t1b.Number = t2b.Number
WHERE t1a.ID = 3
GROUP BY t1b.ID
HAVING COUNT(*) = (SELECT COUNT(*) FROM Table1 WHERE ID = t1a.ID)
select t11.ID as Id_To_Find,t12.ID as Id_Found
from Table1 t11
join (
select t21.Number as Found,t22.Number as ToFind from Table2 t21
left join Table2 t22 on t21.Code = t22.Code
and t21.Att1 = t22.Att1
and t21.Att2 = t22.Att2
and t21.Att3 = t22.Att3
and t21.Number <> t22.Number
group by t21.Number,t22.Number
having COUNT(*) = (select COUNT(*) from Table2 where Number = t22.Number))
as FindMatches
on t11.Number = FindMatches.ToFind
join Table1 t12 on t12.Number = FindMatches.Found
Kind of hard to understand what you're trying to acheive. As i understood from your example, you want to match the Number for the input ID in Table1 with any column (correct?) in Table2.
With input ID=3, the SELECT will return Number=7. In the IN (...)-condition, you can specify whichever columns in Table2 you want to match to Table1.Number.
DECLARE #Input INT = 3 -- Your input
SELECT DISTINCT t1.Number
FROM Table1 t
INNER JOIN Table2 t2 ON t.Number IN (t2.Number, t2.Code, t2.Att1, t2.Att2, t2.Att3)
INNER JOIN Table1 t1 ON t2.Number = t1.Number AND t.ID <> t1.ID
WHERE t.ID = #Input

select data having same id

id idtest result
1 1 2
1 2 1
1 3 2
2 1 2
2 2 1
2 3 1
3 1 1
3 2 2
3 3 1
Would like to get all the rows with the same IDs that matches the condition.
For example: get all the rows with the same id where (idTest=2 and result=1) and (idTest=3 and result=2)
result:
id idtest result
1 1 2
1 2 1
1 3 2
What would be the query???
Thanks!
Do you mean this?
SELECT * FROM table WHERE id = 1 and (result = 1 OR result = 2)
How about his:
SELECT *
FROM table WHERE (idTest = 2 OR idTest = 3) AND (result=1 OR result=2)
ID test res
1 1 2
1 2 1
1 3 2
2 1 1
2 2 2
2 3 2
3 1 1
3 2 2
3 3 1
Sorry. This would be my table. and Would like to get all the rows with the same IDs that matches the condition. For example: get all the rows with the same id where (test=2 and res=1) and (test=3 and res=2)
Result:
ID test res
1 1 2
1 2 1
1 3 2
What would be the query in order to get the three rows ?? Thanks!
You can use EXISTS:
SELECT id, idTest, result
FROM dbo.TableName t
WHERE EXISTS
(
SELECT 1 FROM dbo.TableName t2
WHERE t.id = t2.id
AND(
( t2.idTest=2 AND t2.result=1 )
OR
( t2.idTest=3 AND t2.result=2 )
)
)
Demo
Update: result is different:
id idTest result
1 1 2
1 2 1 <-- satisfies your condition
1 3 2 <-- satisfies your condition
2 1 2
2 2 1 <-- satisfies your condition
2 3 1
So either my understanding was incorrect or your expected result. I have also all ID=2 because the second id-2 row matches the condition.
You seem to want all rows for id's that have rows with that particular combination. What about:
with ids as (
select id
from mytable
where (idTest=2 and result=1) or (idTest=3 and result=2)
group by id
having count(id) = 2
)
select mytable.* from mytable
inner join ids
on ids.id = mytable.id
This gets a list of id's where both conditions apply, and then gets all rows for those id's.
SqlFiddle
SELECT *
FROM table t1
WHERE EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 2 AND result = 1)
AND EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 3 AND result = 2)
Just keep adding more AND EXISTS if you need more
Or you can use IN if it makes more sense to you
SELECT *
FROM table
WHERE id IN (SELECT id from table where idtest = 2 and result = 1)
AND id IN (SELECT id from table where idtest = 3 and result = 2)
do you need a method that treats the condition(s) in a generic way, like if they're values in another table? Or do you only need a way to pull results of two independent conditions?
If the latter, then this should work:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=2 AND RESULT=1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=3 AND RESULT=2) cond2 ON
cond1.id = cond2.id
otherwise, if your conditions are generic and stored in a table, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 1 AND idTest=c.idTestVal AND result=c.resultVal) cond1 INNER JOIN
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 2 AND idTest=c.idTestVal AND result=c.resultVal) cond2 ON
cond1.id = cond2.id
if the 4 values are passed in as parameters, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=#idTestVal1 AND result=#resultVal1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=#idTestVal2 AND result=#resultVal2) cond2 ON
cond1.id = cond2.id

SQL Join with multiple row condition in second table

I have a question on SQL join which involve multiple condition in second joined table. Below is the table details
Table 1
pId status keyVal
---- ------- ------
100 1 45
101 1 46
Table 2
pId mode modeVal
100 2 5
100 3 6
101 2 7
101 3 8
I have above two tables and I am trying to join based on below condition to get pId's
pId's which has keyVal = 45 and status = 1 joined with table2 which has mode = 2 and modeVal 5 and mode =3 and modeVal = 6
the result I am expecting is to return pid = 100
Can you please help me with a join query ?
One way is to use GROUP BY with HAVING to count that the number of rows found is 2, of which 2 are matching the condition;
WITH cte AS (SELECT DISTINCT * FROM Table2)
SELECT t1."pId"
FROM Table1 t1 JOIN cte t2 ON t1."pId" = t2."pId"
WHERE t1."status" = 1 AND t1."keyVal" = 45
GROUP BY t1."pId"
HAVING SUM(
CASE WHEN t2."mode"=2 AND t2."modeVal"=5 OR t2."mode"=3 AND t2."modeVal"=6
THEN 1 END) = 2 AND COUNT(*)=2
If the values in t2 are already distinct, you can just remove the cte and select directly from Table2.
An SQLfiddle to test with.
SELECT columns
FROM table1 a, table2 B
WHERE a.pid = B.pid
AND a.keyval = 45
AND a.status = 1
AND (
(B.mode = 2 AND B.modeval = 5)
OR
(B.mode = 3 AND B.modeval = 6)
)
Below query should work for you perfectly
select distinct table1.pid FROM table1 JOIN table2
on table1.pid = table2.pid
WHERE table2.modeValue IN (5,6) AND table2.mode IN (2,3) AND table1.keyVal=45 and table1.status=1;