Multiple Joins and Subquery with Not Exists - sql

I want to delete records from the BETA TABLE that doesn't exist in the ALPHA Table as well as excludes the records obtained by the inner join of CHARLIE and DELTA tables.
This is the query for A & B
SELECT B.* from ALPHA A right join
BETA B ON A.ID= B.ID
where A.ID is NULL
This gives me the records of BETA Table that don't exist in Alpha Table
Now my second query is
SELECT C.* FROM CHARLIE C INNER JOIN
DELETE D ON
C.ID=D.ID
This gives me the records from the inner join of CHARLIE AND DELTA
I have tried using the query below, but it doesn't work and doesn't delete anything
DELETE B
From ALPHA A right join
BETA B ON A.ID = B.ID
where A.ID is NULL AND NOT EXISTS
( SELECT C.* FROM CHARLIE C INNER JOIN DELTA D ON
C.ID = D.ID WHERE B.ID = C.ID )
I would really appreciate any help.

I have solutions for you using "IN" and "Exists". Please check and let me know.
DECLARE #ALPHA TABLE( ID INT,VAL1 DECIMAL(18,2),VAL2 DECIMAL(18,2));
DECLARE #BETA TABLE( ID INT,VAL1 DECIMAL(18,2),VAL2 DECIMAL(18,2));
DECLARE #CHARLIE TABLE( ID INT,VAL1 DECIMAL(18,2),VAL2 DECIMAL(18,2));
DECLARE #DELTA TABLE( ID INT,VAL1 DECIMAL(18,2),VAL2 DECIMAL(18,2));
------------------------USING IN-------------------------------
DELETE FROM #BETA
WHERE ID IN (SELECT B.ID from #ALPHA A right join #BETA B ON A.ID= B.ID
WHERE A.ID is NULL )
OR ID IN (SELECT C.ID FROM #CHARLIE C INNER JOIN #DELTA D ON C.ID=D.ID)
-------------------Using Exists--------------------
DELETE FROM #BETA
WHERE Exists (SELECT B.* from #ALPHA A right join #BETA B ON A.ID= B.ID
where A.ID is NULL )
OR Exists (SELECT C.* FROM #CHARLIE C INNER JOIN #DELTA D ON C.ID=D.ID)
Note: I have used Sql table variables instead of Normal table.

Just use not exists/exists for both. I am not sure what "as well as excludes the records obtained by the inner join of CHARLIE and DELTA tables".
If you want to delete records where both conditions are met, then
DELETE B FROM BETA B
WHERE NOT EXISTS (SELECT 1 FROM ALPHA A WHERE A.id = B.ID
) OR
EXISTS (SELECT 1
FROM CHARLIE C INNER JOIN
DELTA D
ON C.ID = D.ID
WHERE B.ID = C.ID
) ;
If you don't want the CHARLIE/DELTA records to be excluded, then use AND NOT EXISTS rather than OR EXISTS.

Related

"On" left join order

I've read through 20+ posts with a similar title, but failed to find an answer, so apologies in advance if one is available.
I have always believed that
select * FROM A LEFT JOIN B on ON A.ID = B.ID
was equivalent to
select * FROM A LEFT JOIN B on ON B.ID = A.ID
but was told today that "since you have a left join, you must have it as A = B, because flipped it will act as an inner join.
Any truth to this?
Whoever told you that does not understand how JOINs and join conditions work. He/She is completely wrong.
The order of the tables matters for a left join. a left join b is different than b left join a, but the order of the join condition is meaningless.
A.ID = B.ID is the condition on which the tables are joined and returns TRUE or FALSE.
Since equality(=) is commutative, the order of the operands does not affect the result.
They are completely incorrect and it is trivial to prove.
DECLARE #A TABLE (ID INT)
DECLARE #B TABLE (ID INT)
INSERT INTO #A(ID) SELECT 1
INSERT INTO #A(ID) SELECT 2
INSERT INTO #B(ID) SELECT 1
SELECT *
FROM #A a
LEFT JOIN #B b ON a.ID=b.ID
SELECT *
FROM #A a
LEFT JOIN #B b ON b.ID=a.ID
The order of the tables matter (A Left JOIN B versus B LEFT JOIN A), the order of the join condition group matter if an OR is used (A=B OR A IS NULL AND A IS NOT NULL - always use parentheses with OR), but within a condition group(a.ID=b.ID for example) it doesn't matter.

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

Select using LEFT OUTER JOIN with condition

I have two tables Table A and Table B
Table A
1. *id*
2. *name*
Table B
1. *A.id*
2. *datetime*
I want to select
1. *A.id*
2. *A.name*
3. *B.datetime*
Even if table B do not contains a row with A.id for specific day and it should replace that column with NULL
e.g
Table A contains
1. *(1 , Haris)*
2. *(2, Hashsim)*
Table B Contains following for today's date.
1. *(1, '2014-12-26 08:00:00')*
I should show 2 results with id 1 and 2 instead of only id 1.
Using LEFT OUTER JOIN with WHERE Clause makes it a LEFT INNER JOIN, how to work around that ?
SELECT A.id, A.name, b.datetime
FROM A
LEFT Outer JOIN B on B.id = A.id
Use LEFT OUTER JOIN to get all the rows from Left table and one that does not have match will have NULL values in Right table columns
SELECT A.id,
A.name,
B.[datetime]
FROM tableA A
LEFT OUTER JOIN tableB B
ON A.Id = B.id
AND B.[datetime] < #date
SELECT a.id, a.name, b.datetime
FROM A
LEFT JOIN B on B.aid = a.id
WHERE coalesce(B.datetie, '1900-01-01') < #MyDateTime
Select A.id,A.name,B.datetime
from tableA A
Left join
(
SELECT B.ID,B.datetime
FROM tableB B
WHERE B.datetime <= 'myDateTime'
)B
ON A.aid = B.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)
)

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