Transitive joins in postgresql - sql

What is the best way to achieve a transitive join in postgresql? Currently, I want to do a full outer join for tables, a, b, and c. My query currently looks like this:
SELECT *
FROM a
FULL OUTER JOIN b
ON a."ID" = b."ID"
FULL OUTER JOIN c
ON a."ID" = c."ID"
I'm running into an issue where some records that match in table B and table C are showing up in different rows in the query output, and I realized that it must be because I have not explicitly joined tables B and C. What is the best way to write a "transitive" query where a=b, a=c, and b=c?
Here is an example of my current output. Right now, when a matching ID exists for just tables B and C, I get 2 different rows:
A ID
B ID
C ID
32
32
null
35
35
35
36
null
36
null
42
null
null
null
42
Here is my desired output:
A ID
B ID
C ID
32
32
null
35
35
35
36
null
36
null
42
42

Use using:
SELECT *
FROM a FULL OUTER JOIN
b
USING ("ID") FULL OUTER JOIN
c
USING ("ID");
If in your real example, the columns have different names:
SELECT *
FROM a FULL OUTER JOIN
b
ON b.id = a.id FULL OUTER JOIN
c
ON c.id = COALESCE(b.id, a.id);

Related

Values from a table that are not in another one

I have two tables, A and B.
A
ID age
1 24
2 25
45 22
B
ID school
34 school1
1 school2
I want to select IDs that are in B but not in A.
I wrote
Select distinct bb.school
From B as bb
Left outer join A as aa
On bb.ID=aa.ID
inner join C as cc
On bb.school=cc.school
This code returns exactly the same number of rows that I would have with an inner join instead of left outer join.
Am I doing something wrong?
Try using not in;
Select * From A Where ID Not In ( Select ID From B )

best way to join by multiple columns and avoid OR in SQL

I need a recommendation.
I have two tables. Table 1 is the main table and table 2 is the table that I initially thought to join Table 1 through a left join, table 2 is much larger than table 1. What would be the best performing way to join Table 1 and Table 2 being the union condition that Column b is equal to column b or that column c is equal to column c and column d is equal to column d, that is, any of these conditions is met but no empty values are met. This without using OR in the left join due to the poor performance it would have and the execution time. I appreciate any help.
Note: table 1 and table 2 is the result of 40 lines query. Database do not support recursive query. The database is sap hana.
Table 1
ID
column b
column c
column d
1
d
g
j
2
e
h
k
3
f
i
Table 2
ID_2
column b
column c
column d
4
d
g
5
k
6
i
Desired Result
ID
column b
column c
column d
ID_2
1
d
g
J
4
2
e
h
k
5
3
f
i
6
Use two left joins:
select t1.*,
coalesce(t2_b.id_2, t2_c.id_2, t2_d.id_2) as id_2
from table1 t1 left join
table2 t2_b
on t1.b = t2_b.b left join
table2 t2_c
on t1.c = t2_d.c and t2_b.b is null
table2 t2_d
on t1.d = t2_d.d and t2_c.c is null;
Note that for optimal performance, you want three indexes:
table2(b, id_2)
table2(c, id_2)
table2(d, id_2)

Need to understand how Multiple joins - Left Outer, Right outer, Full outer joins work in a single SQL Query

I have four tables - A,B,C,D. Each table has 1 column: ID.
Data:
Table A = 1,2,3,4
Table B = 1,2,4,5
Table C = 2,3,4,5
Table D = 1,3,5,7
I need help in understanding the output of this SQL query:
select d.*, c.*, b.*,a.*
from d
left join c on d.id = c.id
right join b on b.id = c.id
full outer join a on a.id = b.id;
I am very clear till the left join, but after that when the subsequent joins are applied, I do not understand how the result changes.
As per #Pieter's answer, we can work systematically through this:
Taking just the first LEFT JOIN:
SELECT D.ID AS D, c.ID AS C
from d
left join c
on d.id = c.id
All of Ds rows are returned. NULLS are present for failed joins on C:
D C
1 NULL
3 3
5 5
7 NULL
Then, adding the right join to B:
SELECT D.ID AS D, c.ID AS C, b.ID AS B
from d
left join c
on d.id = c.id
right join b
on b.id = c.id
All of Bs rows are returned, with both C and D being NULL where the join fails.
Only 5 is common to D, C and B.
D C B
NULL NULL 1
NULL NULL 2
NULL NULL 4
5 5 5
Finally, the FULL OUTER JOIN back to A will add missing rows from either side of the JOIN.
This means the '3' from A not present in B is added back, with NULLs for the other columns
D C B A
NULL NULL 1 1
NULL NULL 2 2
NULL NULL 4 4
5 5 5 NULL
NULL NULL NULL 3
Imagine it as a SQL stack machine. Push tables onto the stack as they are encountered, left-to-right, in the FROM clause and perform the join on the two top-most tables as ON clauses are encountered. The result of each join is pushed onto the stack also as it is generated.

How to find difference of two columns using in Left Outer Join in SQL Sever 2005?

I have two Tables
Let suppose A and B
Now suppose the structure of table A is Like that
id stock
37 1
40 1
37 1
40 1
37 1
37 1
And B is like that
id stock
37 1
37 1
40 1
Now i want to write a query that give me sum of specific id stock in (table A - Table B) and if that id does not exist in table B then only stock from A.
So i will expect result like that
id stock
40 1
37 2
I thought that left join will be possible option here and i write query like that
SELECT A.id,
SUM(CAST(isNull(A.Stock, 0) as int) - CAST(isNull(B.Stock, 0) as int) )'Stock'
from A
LEFT OUTER JOIN
B
ON A.id = B.id
group by A.id
But Problem is that the above query gives desired records but wrong quantity/Stocklevel as shown below:
id stock
37 0
40 1
How can I resolve Stock Level issue.
I guess you are looking for something like this.
select A.id, A.SumA - coalesce(B.SumB, 0) as stock
from (
select A.id, sum(A.stock) as SumA
from A
group by A.id
) as A
left outer join
(
select B.id, sum(B.stock) as SumB
from B
group by B.id
) as B
on A.id = B.id
Result:
id stock
----------- -----------
37 2
40 1
SE Data
SELECT A.id, A.Stock - isNull(B.stock, 0) as Stock from A
LEFT OUTER JOIN B
ON A.id = B.id
That would be it I think.
PS. you group by something that you did not include in your case scenario. Your expected result is also not understandable to me (it conflicts with your problem description)

Transposing rows to columns using self join

I have a table named category with values as below,
CategoryId | Value | Flag
1 25 a
2 26 a
3 27 a
1 28 m2 23 m
1 36 p2 33 p
Now I want to transpose the rows present in this table to columns based on the flag, something like
CategoryId | aValue | mValue | PValue
1 25 28 36
2 26 23 33
3 27 null null
I am trying to join based on the category id but I am just getting the matched records (inner join) in my resultset even if I use left outer join in my query.
My query:
SELECT
A.CategoryId,
A.Value AS actual,
B.Value AS projected,
C.Value AS Manual
FROM ((a AS A left JOIN b AS B ON A.categoryid=B.categoryid)
left JOIN c AS C ON A.categoryid=C.categoryid)
WHERE (((A.flag)="a") and ((B.flag)="p") and ((C.flag) ="m"))
I am getting the proper results if I have the data in 3 different tables.
I just want to check what would be the best way to transpose a rows to column when using self join...
Thanks,
Barani
Try this:
SELECT CategoryId,
MIN(SWITCH(YourTable.Flag = 'a',Value)) AS aValue,
MIN(SWITCH(YourTable.Flag = 'm',Value)) AS mValue,
MIN(SWITCH(YourTable.Flag = 'p',Value)) AS pValue
FROM YourTable
GROUP BY CategoryId