SQL multiple table join - sql

I have three tables A, B, and C:
A
---------
a_pk | id
B
----------------------
b_pk | id | link | foo
C
----------------------
c_pk | id | link | bar
All records in B have a matching record in A; all records in C have a matching record in A, but records in B and C do not necessarily have to match each other. I want to get the set of results where A has a match in either B or C. Individually, the queries would be:
SELECT A.id, B.foo FROM A INNER JOIN B ON A.id = B.id
SELECT A.id, C.bar FROM A INNER JOIN C ON A.id = C.id
SELECT B.foo, C.bar FROM B FULL JOIN C ON B.id = C.id AND B.link = C.link
What would I need to fill in to make this work?
SELECT A.id, B.foo, C.bar FROM <join A, B, C>
I'm using Oracle if it makes a difference, and I would prefer to avoid using a subquery if possible.
[edit - for clarification]
I want only the records from A that have a match in either B or C.

Sounds like you need a left join. (I'm not very familiar with Oracle but I assume this should work.)
SELECT A.id, B.foo, C.bar
FROM A
LEFT OUTER JOIN B on A.id = B.id
LEFT OUTER JOIN C on A.id = C.id
WHERE B.id IS NOT NULL OR C.id IS NOT NULL

Related

JOIN on column only if NOT NULL

I'm in the process of re-writing an old SQL query and have troubles making sense out of it. It contains several conditions of the form
SELECT ...
FROM a, b, c
WHERE
c.id = ...
AND (
a.x_id IS NULL
OR a.x_id = c.x_id
)
AND b.id = a.b_id (+)
Can this query be rewritten using proper JOIN syntax? Is it equivalent to the following or will it produce different results under certain circumstances?
SELECT ...
FROM b
LEFT JOIN a
ON b.id = a.b_id
LEFT JOIN c
ON a.x_id = c.x_id
WHERE c.id = ...
The original query is 100 lines long and spans 5 tables, plus several joins over "virtual tables" (i.e. where conditions of the form x.z_id = y.z_id), which makes it hard to break down into more manageable bits or debug.
if you want same result as you have in first query - you must make left join only with table a, like this :
SELECT ...
FROM b, c
LEFT JOIN a
ON b.id = a.b_id and b.id = a.b_id
WHERE
c.id = ... b.c_id
or if you want the same style with all tables, you can use inner join with table b, like this :
SELECT ...
FROM c
INNER JOIN b
on b.c_id = c.id
LEFT JOIN a
ON b.id = a.b_id
WHERE
c.id = ...
in my both query we select data from table b where column is not null

Join on 3 tables

i have currently 3 tables :
Table A
Table B
Table C
There is a link between A & B and a link between B & C (A-B-C).
The thing is that :
It is possible to have a row in A but no not in B
It is possible to have a row in B but not in A
It is possible to have a row in B but not in C
In the end i would like to have a query which could give me the following row (where X represent the ID of the corresponding table) :
TableA|TableB|TableC
X | X | X
X | null | null
null | X | X
X | X | null
I managed to have the case with TableA & TableB with the following query :
SELECT A.ID, B.ID
FROM TABLEA A
LEFT JOIN TABLEB B on (join condition)
UNION
SELECT A.ID,B.ID
FROM TABLE B
LEFT JOIN TABLEA A on (join condition)
Thank you for any help you may provide
What you need is a FULL OUTER JOIN, however, you have tagged your post with sybase - it depends what you mean by that. Sybase ASE doesn't support FULL OUTER JOIN syntax, but SQL Anywhere does.
If I understood it correctly then a FULL OUTER JOIN should do your work :
SELECT a.id,b.id,c.id
FROM TableA a
FULL OUTER JOIN TableB b on a.id = b.id
FULL OUTER JOIN TableC c on COALESCE(a.id,b.id) = c.id
SQL Fiddle

Postgresql: inner join on 3 tables if data in 2. table is of no interest

Assuming I have the following three tables:
a
------
id
p1
b_id
b
------
id
c_id
other_value
c
------
id
p2
To get all the p1 and p2 values, I would write the following query:
SELECT
a.p1, c.p2
FROM
a
INNER JOIN
b ON (a.b_id = b.id)
INNER JOIN
c ON (b.c_id = c.id)
Now, since I'm not really interested in the other_value inside of b, I wondered if there is a simpler way to find the corresponding p2 value for each a entry.
(The reason for this question is that I'm running into performance problems on a database with a similar, but more complex, structure)
If you really insist on avoiding the b table in the outer scope, here is a nice ugly solution:
SELECT *
-- a.p1, c.p2
FROM a,c
WHERE EXISTS (
SELECT 42
FROM b
WHERE b.id = a.b_id
AND b.c_id = c.id
);
The same, using JOIN syntax (yields exactly the same query plan)
SELECT *
FROM a
JOIN c ON EXISTS (
SELECT 42
FROM b
WHERE b.id = a.b_id
AND b.c_id = c.id
);

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

Inner joining one table against many others

I have a table A with columns (Id,Value)
and a table B with Columns (BId,Id,..)
and a table C with columns (CId,Id,...)
I need to perform an inner join on these tables as follows
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
inner join C c on c.Id=a.Id
where <many conditions on table B and C>
How can i achieve the same. Now when i just run the query
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
inner join C c on c.Id=a.Id
it doesnt return anything.. please help.
FYI when i run the joins separately it gives me the rows. I just want a union of them...
Sample data:
A
1
2
3
B
2
C
3
then i want to select
A
2
3
Thanks in advance.
So, following your comments, it appears that you want something like this:
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
where <many conditions on table B>
UNION ALL
SELECT a.Id, a.Value from A
inner join C c on c.Id=a.Id
where <many conditions on table C>
As long as the fields match on ID from A -> B and A -> C and you dont have any other join condition, you should be able to see the matching rows.
I could not understand your point about how the B and C Id do not match. if a.id=b.id and a.id=c.id, Doesn't it automatically imply b.id = c.id?
Anyways, in situations like these, I try to do outer join of A on B and C and see if the rows that I think are matching in fact do exist.
select a.Id,a.Value from A a
left outer join B b on b.Id=a.Id
left outer join C c on c.Id=a.Id
where (b.id is not null or c.id is not null)
/* Matching record found in b or c */
EDIT: Based on your requirement, you can use the approach that Lamak suggested above (Using UNION Alls) or if you are certain that for each record in A, you will only have one record in B and one in C at most and only one column, you can use the scalar sub query approach.