SQL join on three tables, lines that exist in 2 tables but not the third - sql

Please I need your help.
Suppose that we have 3 tables A, B and C as shown in the image below:
I want to get lines in the table A that exist or not exist in table B, and lines in table C that exist or not exist in table B, using one sql request.
I have tried this but doesn't work :
SELECT A.ATS0804, C.ATS0207, A.ATS0959, A.ATS0802, B.ATS0827
FROM
ISUT183.ENS0042 B
RIGHT JOIN ISUT183.ENS0038 A
ON B.ENS0038K = A.ATS0804
RIGHT JOIN ISUT183.EN00041 C
ON B.EN00041K = C.AT02812
WHERE ( C.ATS0207 = '0001757430'
AND B.ATS0823 = '9999-01-01'
AND A.ATS0803 = '9999-01-01'
AND A.ATS0959 = '61384352001'
AND A.ATS0802 ='01.01.2010'
) ;

you can do a cross join too:
with AB as (
select * from A left outer join B on A.ID1=B.ID1
),
AC as (
select * from C left outer join B on C.ID2=B.ID2
)
select * from AB CROSS JOIN AC

use where exists and where not exists clauses

If you test equality into table B in where clause, the left outer join or right outer join dont take null
You dont have join between A and C, then you can do a UNION ALL
but you must take columns of same type in selects clause (ID1 same type of ID2)
select * from (
select 'A-B' typejoin, A.ID1 as IDA_OR_C, B.ID1 as IDB from A left outer join B on A.ID1=B.ID1
union all
select 'A-C' typejoin, C.ID2 as IDA_OR_C, B.ID2 as IDB from C left outer join B on C.ID2=B.ID2
) tmp
where ....

Related

Pull columns from series of joins in SQL

I am kind of stuck at one problem at my job where I need to pull 2 cols from base table and 1 column from a series of joins.
Please note that, I can not provide real data so I am using dummy column/table names and there are 100s of columns in real project.
Select A.Name,B.Age, D.Sal
From A Left join B on A.iD=B.id and B.Date=CURRENT_DATE
(/* join A and B table and return distinct column which is B.XYZ)
inner join C on C.iD=B.XYZ
(/* join B and C take C.YYY column for next join */)
inner join D on D.id=C.YYY
(/* Take out the D.Sal column from this join */) where A.Dept='IT'
I have written this query but it is taking forever to run because B.XYZ column has a lot of duplicates. how can I get distinct of B.XYZ column from that join.
For Joining Table B, you first get a distinct table of the columns you need from B then join.
SELECT
A.Name,
B.Age,
D.Sal
From A
LEFT JOIN ( -- Instead of all cols (*), just id, Date, Age and xyz might do
SELECT DISTINCT * FROM B
) B ON A.iD = B.id AND B.Date = CURRENT_DATE
--(/* join A and B table and return distinct column which is B.XYZ */)
INNER JOIN C ON C.iD = B.XYZ
--(/*join B and C take C.YYY column for next join */)
INNER JOIN D ON D.id = C.YYY
--(/* Take out the D.Sal column from this join */)
WHERE A.Dept='IT'
You say you get the same rows multifold, because for a b.id, date and age you get the same xyz more than once, or so I understand it.
One option is to join with a subquery that gets the distinct data:
SELECT a.name, b.age, d.sal
FROM a
LEFT JOIN
(
SELECT DISTINCT id, date, age, xyz FROM b
) dist_b ON dist_b.id = a.id and dist_b.date = CURRENT_DATE
INNER JOIN c ON c.id = dist_b.xyz
INNER JOIN d ON d.id = c.yyy
WHERE a.dept = 'IT';
Of course you can even move the date condition inside the subquery:
SELECT a.name, b.age, d.sal
FROM a
LEFT JOIN
(
SELECT DISTINCT id, age, xyz FROM b WHERE date = CURRENT_DATE
) dist_b ON dist_b.id = a.id
INNER JOIN c ON c.id = dist_b.xyz
INNER JOIN d ON d.id = c.yyy
WHERE a.dept = 'IT';
Your LEFT OUTER JOIN doesn't work by the way. As you are inner joining the following tables, a match must exists, so your outer join becomes an inner join. For the outer join to work you would have to outer join the following tables, too.

Multiple tables joined to a table via single column

I am trying to create query, on below scenario.
with my skills I am able to join Table A,A1,B and A,A1,C and A,A1,D individually and union them.
Is there any better way to achieve same. I am using Oracle as Database.
It all depends on what they mean and if you need to know the columns the values are from.
This would get all the columns and you would have NULL values from the non-matching B, C, D tables:
SELECT *
FROM a1
INNER JOIN a ON a1.aid = a.id
LEFT OUTER JOIN b ON a.extid = b.extid
LEFT OUTER JOIN c ON a.extid = c.extid
LEFT OUTER JOIN d ON a.extid = d.extid
Or, this would get only the relevant values and give you the type they belong to in fewer columns:
SELECT *
FROM a1
INNER JOIN a ON a1.aid = a.id
INNER JOIN (
SELECT extid, 'B' AS type, pqr_col AS col1, qrs_col AS col2 FROM b
UNION ALL
SELECT extid, 'C', abc_col, bcd_col FROM c
UNION ALL
SELECT extid, 'D', xyz_col, yza_col FROM d
) bcd
ON a.extid = bcd.extid
Union was my first thought when I read your question. Though, for simplicity, you could first create a view and then join it to other table(s):
create view v_ext as
select b.extid, b.pqr_col, b.qrs_col from b
union all
select c.extid, c.abc_col, c.bcd_col from c
union all
select d.extid, d.xyz_col, d.yza_col from d;
select *
from a join a1 on a.id = a1.aid
join v_ext v on v.extid = a.extid;
you can try the query with 'with' clause. Something like below, I havent tested it though
with union_output as
( select b.extid, b.pqr_col, b.qrs_col from b
union
select c.extid, c.abc_col, c.bcd_col from c
union
select d.extid, d.xyz_col, d.yza_col from d)
select *
from a join a1 on a.id = a1.aid
join union_output uo on uo.extid = a.extid;
Select *from tableA A
Inner join tableA1 A1 on A1.A1ID=A.AID
Inner join tableB b on b.ExtID=A.ExtID
Inner join tableC c on c.ExtID=A.ExtID
Inner join tableD d on d.ExtID=A.ExtID

SQL - not sure how to join tables

I'm trying to join two tables like this:
Table A
ID Value1
1 A
2 B
3 C
Table B
ID Value2
1 A
3 B
4 C
Result should be:
ID Value1 Value2
1 A A
2 B null
3 C B
4 null C
I.e. join Table A to Table B on ID. If ID doesn't exist in Table A, add the ID from Table B.
The closest I've come is:
SELECT
a.ID, a.Value1, b.Value2
FROM
TableA a
OUTER JOIN
TableB b ON a.ID = b.ID
That gives me the new rows from TableB, but the ID is null.
How can I accomplish this?
You are very close, you just need a little push in the right direction:
SELECT COALESCE(a.ID, B.ID) As ID, a.Value1, b.Value2
FROM TableA a
FULL OUTER JOIN TableB b ON a.ID=b.ID
The COALESCE function returns the first parameter it gets that is not null. since this is a full outer join, a.id will be null on one row and b.id would be null on a different row.
Try this:
SELECT *
FROM TableA A
FULL OUTER JOIN TableB B
ON A.ID = B.ID;
Just a note: you should not name your tables in SQL with spaces in them.
Remember the basic for joining different tables
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name=table2.column_name;
For your case:
SELECT a.value1, b.value2
FROM TableA a
FULL OUTER JOIN TableB b ON a.ID=b.ID
remember full outer join
The FULL OUTER JOIN keyword returns all rows from the table (tableA) and from the table (tableB) and the FULL OUTER JOIN keyword combines the result of both LEFT and RIGHT joins.

Stuck on multiple table filtering query

Ok so I will try to simplify the problem that I have.
I have 4 tables:
TableA:
OneID
TableB:
OneID (FK to TableA)
TwoID (FK to TableC)
TableC:
TwoID
ThreeID (FK to TableD)
TableD:
ThreeID
I need a query to retrieve data from all 4 of these tables.
The query criteria is:
want to inner join tables A, B, C
want to join above result with table D with the following conditions:
if a record is in Table D but not in Table C, then it must always be present in the results
otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
The scenario you have described is not really possible (or at least they are not really logical)
if a record is in Table D but not in Table C, then it must always be present in the results
The only way a record could be "in Table D and not in Table C" is if the foreign key is null in table D, with no link from table D to tables A or B there is no other way you could define a record as being present in D and not in C:
otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
Again, the only way this could happen is with NULLABLE foreign keys. Regardless I think any of the below will get you the results you require:
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM D
LEFT JOIN (C
INNER JOIN B
ON B.TwoID = C.TwoID
INNER JOIN A
ON A.OneID = B.OneID)
ON C.ThreeID = D.ThreeID;
Or
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
RIGHT JOIN D
ON D.ThreeID = C.ThreeID
Or
SELECT A.OneID, B.TwoID, c.ThreeID, D.FourID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
INNER JOIN D
ON D.ThreeID = C.ThreeID
UNION ALL
SELECT NULL, NULL, NULL, FourID
FROM D
WHERE ThreeID IS NULL;
Examples on SQL Fiddle
The first two have the same execution plan, it is just a matter of preference, I personally dislike using RIGHT JOIN because it makes queries feel like they in the wrong order i.e bottom to top, but this is purely my preference. The last query may perform better depending on the cardinality of your data and any indexes you have
EDIT
With your revised criteria I think the easiest way to implement this is with a UNION ALL:
SELECT A.OneID, B.TwoID, c.ThreeID, d3 = D.ThreeID
FROM A
INNER JOIN B
ON B.OneID = A.OneID
INNER JOIN C
ON C.TwoID = B.TwoID
INNER JOIN D
ON D.ThreeID = C.ThreeID
UNION ALL
SELECT NULL, NULL, NULL, ThreeID
FROM D
WHERE NOT EXISTS (SELECT 1 FROM C WHERE C.ThreeID = D.ThreeID);
Example on SQL Fiddle
I am not 100% sure I understood you correctly but I will try to help anyway. It seems that you need to do FULL OUTER JOIN on table D:
SELECT
*
FROM
TableA AS A INNER JOIN
TableB AS B ON B.A_Id = A.Id INNER JOIN
TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN
TableD AS D ON D.C_Id = C.Id
If I have misunderstood your requirements and you need more complicated criteria, you could just do FULL OUTER JOIN on all the tables and put extra conditions in WHERE part:
SELECT
*
FROM
TableA AS A FULL OUTER JOIN
TableB AS B ON B.A_Id = A.Id FULL OUTER JOIN
TableC AS C ON C.B_Id = B.Id FULL OUTER JOIN
TableD AS D ON D.C_Id = C.Id
WHERE
--if a record is in Table D but not in Table C, then it must always be present in the results
(D.Id IS NOT NULL AND C.Id IS NULL) OR
(
--otherwise if a record is in Table D and Table C, then it should only be present if it is in the result of the A,B,C join
(D.Id IS NOT NULL AND C.Id IS NOT NULL) AND
--want to inner join tables A, B, C
(A.Id IS NOT NULL AND B.Id IS NOT NULL AND B.Id IS NOT NULL)
)

Join two tables with one table

I need to do the following (I am not really sure if it is possible to do using SQL)
Table A
col_a_1, col_a_2, col_a_3
Table B
col_a_1, col_b_1, col_b_2....
Table C
col_a_1, col_c_1, col_c_2....
were col_a_1 is unique in table A. I need to join tables A, B, C such that every entry in table A will appear multiple times but every entry in table B and C appears only once and against the same col_a_1 of table A.
I know how to do it using the code. Is it also possible to do with SQL alone?
Thanks in advance.
You either want to use an outer join of some sort. either left or full outer.
SELECT A.*, B.*, C.*
FROM Table_A A
LEFT JOIN Table_B B on A.col_A_1 = B.Col_A_1
LEFT JOIN table_C C on A.Col_A_1 = C.Col_A_1
SELECT A.*, B.*, C.*
FROM Table_A A
FULL OUTER JOIN Table_B B on A.col_A_1 = B.Col_A_1
FULL OUTER JOIN table_C C on A.Col_A_1 = C.Col_A_1
or possibly a union result... just depends on what you're after.
SELECT A.*, B.*
FROM Table_A A
INNER JOIN Table_B B on A.col_A_1 = B.Col_A_1
UNION
SELECT A.*, C.*
FROM Table_A A
INNER JOIN Table_C C on A.col_A_1 = C.Col_A_1