Oracle joining multiple tables? - sql

I am trying to do the following
select
TA.C1 ,TB.C1 ,TC.C1
from TableA TA ,TableB TB , TableC TC
where TA.C1 = "ABC"
AND TA.C2 = TB.C1
and TA.C3 = TC.C1
Result is
My aim is to add a couple more tables to this query
select
TA.C1,TB.C1,TC.C1,TD.C1,TE.C1
from TableA TA ,TableB TB , TableC TC , TableD TD, TableE TE
where TA.C1 = "ABC"
and TA.C2 = TB.C1
and TA.C3 = TC.C1
and TA.C4 = TD.C1
and TD.C2 = TE.C1
But since the Column TD.C1 contains null values , whereas TA.C4 always has some values , I get the below results.
The expected result is
I have tried joining using Joins for joining 4 tables :
select
TA.C1,TB.C1,TC.C1,TD.C1
from TableA TA
JOIN TableB TB ON (TA.C2 = TB.C1)
JOIN TableC TC ON (TA.C3 = TC.C1)
LEFT JOIN TableD TD ON (TA.C4 = TD.C1)
AND TA.C1 = "ABC"
The results is pretty near what I expect:
The issue is I'm not sure how to Join the 5th table (Table E) as this doesn't have any joing with Table A.

You can just include table E with another left join to table D. Basically, the relation exists between tables D and E, and data entered into it has to be in accordance with it. If there is no data, the relation still exists, so the join will return nulls as you want.
select
TA.C1,TB.C1,TC.C1,TD.C1, TE.C1
from TableA TA
INNER JOIN TableB TB ON (TA.C2 = TB.C1)
INNER JOIN TableC TC ON (TA.C3 = TC.C1)
LEFT JOIN TableD TD ON (TA.C4 = TD.C1)
LEFT JOIN TableE TE ON (TD.C2 = TE.C1)
AND TA.C3 = "ABC"

Best practice: Use explicit joins as you are in you later example.
When joining multiple tables the join need not all start with the same table, each one must simply be related. That is you can
select *
from a
inner join b on a.id = b.id_a
inner join c on b.id = c.id_b

Related

MS Acces Jet SQL Error: Join Expression not supported with multiple Join conditions

I'm trying to run this SQL Expression in Access:
Select *
From ((TableA
Left Join TableB
On TableB.FK = TableA.PK)
Left Join TableC
On TableC.FK = TableB.PK)
Left Join (SELECT a,b,c FROM TableD WHERE b > 1) AS TableD
On (TableD.FK = TableC.PK AND TableA.a = TableD.a)
but it keeps getting error: Join-Expression not supported.
Whats the problem?
Sorry, im just starting with Jet-SQL and in T-SQL its all fine.
Thanks
The issue is that the final outer join condition TableA.a = TableD.a will cause the query to contain ambiguous outer joins, since the records to which TableA is joined to TableD will depend upon the results of the joins between TableA->TableB, TableB->TableC and TableC->TableD.
To avoid this, you'll likely need to structure your query with the joins between tables TableA, TableB & TableC existing within a subquery, the result of which is then outer joined to TableD. This unambiguously defines the order in which the joins are evaluated.
For example:
select * from
(
select TableA.a, TableC.PK from
(
TableA left join TableB on TableA.PK = TableB.FK
)
left join TableC on TableB.PK = TableC.FK
) q1
left join
(
select TableD.a, TableD.b, TableD.c, TableD.FK from TableD
where TableD.b > 1
) q2
on q1.a = q2.a and q1.PK = q2.FK
Consider relating every join to the FROM table to avoid having to nest relations.
SELECT *
FROM ((TableA
LEFT JOIN TableB
ON TableB.FK = TableA.PK)
LEFT JOIN TableC
ON TableC.FK = TableA.PK)
LEFT JOIN
(SELECT FK,a,b,c
FROM TableD WHERE b > 1
) AS TableD
ON (TableD.FK = TableA.PK)
AND (TableD.a = TableA.a)

How to Improve Updating a Table's Fields That are Referenced in Subqueries

I have a table that is truncated, then loaded with several hundreds of thousands of records each time by a process. The next process needs to update several columns for each record (that don't have values) by basically looking up values from various other tables while utilizing some of the existing updating table's own columns as the reference (in example below, this could be TABLE_A.P1 and TABLE_A.P2), e.g.:
UPDATE TABLE_A A SET
A.COL1 = (
SELECT B.COL_BX
FROM TABLE_B B
WHERE B.P1 = A.P1 -- Reference back to the updating table's column
),
A.COL2 = (
SELECT D.COL_DY
FROM TABLE_C C INNER JOIN TABLE_D D
ON C.H1 = D.H1
WHERE C.P1 = A.P1 -- Reference back to the updating table's column
-- Would this act as a join between A and C (not implementation-wise but rather functionality)?
),
A.COL3 = (
SELECT G.COL_GZ
FROM TABLE_E E INNER JOIN TABLE_F F
ON E.N1 = F.N1
OUTER JOIN TABLE_G G
ON G.M1 = F.M1
WHERE E.P1 = A.P1
AND E.P2 = A.P2
-- AND (bunch of other predicate for G columns)
); -- There are more columns to be updated but omitted for brevity
When I run such update, the session times out. My question is, is there a better way to write this update given the above scenario?
You might find that separate update statements are faster:
UPDATE TABLE_A A
SET A.COL1 = (SELECT B.COL_BX
FROM TABLE_B B
WHERE B.P1 = A.P1);
UPDATE TABLE_A A
SET A.COL2 = (SELECT D.COL_DY
FROM TABLE_C C
INNER JOIN TABLE_D D
ON C.H1 = D.H1
WHERE C.P1 = A.P1);
UPDATE TABLE_A A
SET A.COL3 = (SELECT G.COL_GZ
FROM TABLE_E E
INNER JOIN TABLE_F F
ON E.N1 = F.N1
LEFT OUTER JOIN TABLE_G G
ON G.M1 = F.M1
WHERE E.P1 = A.P1 AND
E.P2 = A.P2);
Best of luck.
You can try the following:
UPDATE TABLE_A
SET TABLE_A.COL1 = B.COL_BX
From
TABLE_A A
INNER JOIN
TABLE_B B
ON B.P1 = A.P1;
UPDATE TABLE_A
SET TABLE_A.COL2 = D.COL_DY
From
TABLE_A A
INNER JOIN
TABLE_C C
ON C.P1 = A.P1
INNER JOIN
TABLE_D D
ON C.H1 = D.H1;
UPDATE TABLE_A
SET TABLE_A.COL3 = G.COL_GZ
From
TABLE_A A
INNER JOIN
TABLE_E E
ON E.P1 = A.P1
AND E.P2 = A.P2
INNER JOIN
TABLE_F F
ON E.N1 = F.N1
LEFT OUTER JOIN
TABLE_G G
ON G.M1 = F.M1;
I don't know the details about your table structure, but you might be able to combine these 3 updates into one like shown below, but it totally depends on your table structure.
UPDATE TABLE_A
SET
TABLE_A.COL1 = B.COL_BX,
TABLE_A.COL2 = D.COL_DY,
TABLE_A.COL3 = G.COL_GZ
From
TABLE_A A
LEFT OUTER JOIN
TABLE_B B
ON B.P1 = A.P1
LEFT OUTER JOIN
TABLE_C C
ON C.P1 = A.P1
LEFT OUTER JOIN
TABLE_D D
ON C.H1 = D.H1
LEFT OUTER JOIN
TABLE_E E
ON E.P1 = A.P1
AND E.P2 = A.P2
LEFT OUTER JOIN
TABLE_F F
ON E.N1 = F.N1
LEFT OUTER JOIN
TABLE_G G
ON G.M1 = F.M1;

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

How to update with inner join in Oracle

Could someone please verify whether inner join is valid with UPDATE statment in PL SQL?
e.g.
Update table t
set t.value='value'
from tableb b inner join
on t.id=b.id
inner join tablec c on
c.id=b.id
inner join tabled d on
d.id=c.id
where d.key=1
This synthax won't work in Oracle SQL.
In Oracle you can update a join if the tables are "key-preserved", ie:
UPDATE (SELECT a.val_a, b.val_b
FROM table a
JOIN table b ON a.b_pk = b.b_pk)
SET val_a = val_b
Assuming that b_pk is the primary key of b, here the join is updateable because for each row of A there is at most one row from B, therefore the update is deterministic.
In your case since the updated value doesn't depend upon another table you could use a simple update with an EXIST condition, something like this:
UPDATE mytable t
SET t.VALUE = 'value'
WHERE EXISTS
(SELECT NULL
FROM tableb b
INNER JOIN tablec c ON c.id = b.id
INNER JOIN tabled d ON d.id = c.id
WHERE t.id = b.id
AND d.key = 1)
update t T
set T.value = 'value'
where T.id in (select id from t T2, b B, c C, d D
where T2.id=B.id and B.id=C.id and C.id=D.id and D.key=1)
-- t is the table name, T is the variable used to reffer to this table

INNER and LEFT OUTER join help

Say I have 3 tables. TableA, TableB, TableC
I need to operate the recordset that is available after a INNER JOIN.
Set 1 -> TableA INNER JOIN TableB
Set 2 -> TableC INNER JOIN TableB
I need the Set 1 irrespective of if Set 2 is empty or not (LEFT OUTER JOIN) comes to mind.
So essentially, I am trying to write a query and have come this far
SELECT *
FROM TableA
INNER JOIN TableB ON ...
LEFT OUTER JOIN (TableC INNER JOIN TableB)
How would I write in SQL Server?
EDIT: In reality, what I am trying to do is to join multiple tables. How would your response change if I need to join multiple tables ex: OUTER JOIN OF (INNER JOIN of TableA and TableB) and (INNER JOIN OF TableC and TableD) NOTE: There is a new TableD in the equation
SELECT * FROM TableA
INNER JOIN TableB ON TableB.id = TableA.id
LEFT JOIN TABLEC ON TABLEC.id = TABLEB.id
I Don't know what columns you are trying to use but it is just that easy
Edit:
Looking at your edit it seems that you are confused about what Joins actually do. In the example I have written above you will recieve the following results.
Columns -> You will get all of the columns for TableA,TableB and TableC
Rows-> You will start off with all of the rows from tableA. Next you will remove all rows from TableA that do not have a matching "id" in Table B.(You will have duplicates if it is not a 1:1 relationship between TableA and TableB).
Now if you take the results from above you will match any records from TableC that match the TableB.id column. Any rows from above that do not have a matching TableC record will get a null value for all of the columns from TableC in the results.
ADVICE- I am betting that only part of this made sense to you but my advice is that you start writing some queries, predict the results and then see if your predictions are correct to see if you understand what it is doing.
What you want isn't a JOIN but a UNION.
SELECT * FROM TableA INNER JOIN TableB ON ...
UNION
SELECT * FROM TableC INNER JOIN TableD ON ...
You can actually add an ordering to your joins just like in a math equation where you might do this: (5 + 4) * (3 + 1).
Given the second part of your question, give this a try:
SELECT
<your columns>
FROM
(TableA INNER JOIN Table B ON <join criteria for A to B>)
LEFT OUTER JOIN
(TableC INNER JOIN Table D ON <join criteria for C to D>) ON
<join criteria for AxB to CxD>
Select * from ((((TableA a inner join TableB b on a.id = b.id)
left outer join TableC c on b.id = c.id)
full outer join TableD d on c.id = d.id)
right outer join TableE e on e.id = d.id)
/* etc, etc... */
You can lose the brackets if you want.
try this..
SELECT *
FROM TableA a
INNER JOIN TableB b ON a.id=b.id
LEFT OUTER JOIN (SELECT *
FROM TableC c
INNER JOIN TableD d on c.id=d.id
) dt on b.id=dt.id
You didn't give your join conditions or explain how the tables are intended to be related, so it's not obvious how this might be simplified.
SELECT a.a_id, b1.b_id b1_id, b2_id, bc.c_id
FROM TableA a JOIN TableB b1 on a.b_id = b1.b_id
LEFT JOIN (SELECT c.c_id, b2.b_id b2_id
FROM TableC c JOIN TableB b2 ON c.b_id = b2.b_id
) bc ON bc.c_id = a.c_id;
Looking at your latest edit, you can do something along the lines of:
SELECT <columns>
FROM (SELECT <columns> FROM TableA JOIN TableB ON <A-B join conditions>)
LEFT JOIN
(SELECT <columns> FROM TableC JOIN TableD ON <C-D join conditions>)
ON <AB-CD join conditions>
Although you don't actually need the inner projections, and can do:
SELECT <columns>
FROM (TableA a JOIN TableB b ON <A-B join conditions>)
LEFT JOIN
(TableC c JOIN TableD d ON <C-D join conditions>)
ON <AB-CD join conditions>
Where the AB-CD join conditions are written in terms of columns of a, b, c, d etc directly.
Since you're using Sql Server, why not create views that help you? Stuffing everything in a gigantic Sql statement can become hard to read. An example view might look like:
create view AandB
as
select *
from A
inner join B on B.aid = A.aid
And the same for CandD. Then you can retrieve the optional join with simple Sql:
select *
from AndB
left outer join CandD on AndB.cid = CandD.cid
If you're interested in rows from both sets, you can do a full join:
select *
from AndB
full outer join CandD on AndB.cid = CandD.cid
Assuming I Understand your question, I think this is what you're asking for:
SELECT *
FROM TableA INNER JOIN TableB on TableA.JoinColumn = TableB.JoinColumn
LEFT OUTER JOIN TableC on TableB.JoinColum = TableC.JoinColumn
INNER JOIN TableD on TableC.JoinColumn = TableD.JoinColumn
Note that the JoinColumn used to join A & B doesn't necesarilly have to be the same column as the one used to join B & C, and so on for C & D.
SELECT *
FROM TableA A
INNER JOIN TableB B ON B.?? = A.?? AND ...
LEFT JOIN TableC C ON C.?? = B.?? AND ...
LEFT JOIN TableB B2 ON B2.?? = C.?? AND ...
LEFT JOIN TableD D ON D.?? = C.?? AND ...
So here's the thing: logically, joins aren't actually between specific tables, they are between a table and the rest of the "set" (of joins and tables). So while you know that there is a 1-to-1 relationship between C and B2 or between C and D, you can't INNER JOIN to C because C could be null from it's LEFT JOIN to B, which will eliminate those rows, effectively undoing your LEFT join.
So basically, any joins to a table that's LEFT outer joined must also be LEFT outer joined. Does this make sense?