SQL Get rows that doesn't appear in another table - sql

I have this SQL problem: I have tables A and B. Table A has columns id and name, Table B amount and id which is a foreign key to table A.id.
I need to return all table A rows that don't have their id stored in table B. Any ideas?
So the complete opposite is:
SELECT *
FROM a
LEFT OUTER JOIN b ON a.id = b.id;
Here row what I need is left out of result

Just add a where clause:
SELECT a.*
FROM a LEFT OUTER JOIN
b
ON a.id = b.id
WHERE b.id IS NULL;
You can also use NOT EXISTS:
select a.*
from a
where not exists (select 1 from b where b.id = a.id);
In most databases, the two methods typically have similar performance.

Related

Best way to eliminate duplicates rows after multiple joins

I'll consider three simple tables. A, B are my entity tables and C is an intermediate table that creates a many-to-many relationship between A & B.
Schemas:
A: (id INTEGER PRIMARY KEY)
B: (id INTEGER PRIMARY KEY)
C: (
A_id INTEGER,
B_id INTEGER,
FOREIGN KEY(A_id) REFERENCES A(id),
FOREIGN KEY(B_id) REFERENCES B(id)
)
Now, consider the below query
SELECT
A.id
FROM A
LEFT OUTER JOIN C
ON (A.id = C.A_id)
LEFT OUTER JOIN B
ON (C.B_id = B.id)
WHERE ...;
This query would result in duplicate values of A.id, which is expected because C might have multiple rows associated with each row of A. My question is what's the best way to eliminate these duplicates and get the A records. I only need the A records.
I am aware of two ways,
-- Using DISTINCT
SELECT
DISTINCT(A.id), ...
FROM A
LEFT OUTER JOIN C
ON (A.id = C.A_id)
LEFT OUTER JOIN B
ON (C.B_id = B.id)
WHERE ...
ORDER BY A.id;
And
-- Or using A.id IN (above query)/ A.id = Any(above query)
SELECT
...
FROM A
WHERE A.id IN (
SELECT
A.id
FROM A
LEFT OUTER JOIN C
ON (A.id = C.A_id)
LEFT OUTER JOIN B
ON (C.B_id = B.id)
WHERE ...
);
I'm using PostgreSQL. I need to include all the tables for filtering, so not joining a table cannot be considered as an improvement. I've analyzed both the queries but I still feel there might be a better way to do this(in terms of performance).
Any help is really appreciated!
I would suggest exists:
SELECT A.id
FROM A
WHERE EXISTS (SELECT 1
FROM C JOIN
B
ON C.B_id = B.id
WHERE A.id = C.A_id AND . . .
)
You can also try following query:
SELECT
a.* -- or whatever columns you need of a
FROM a
WHERE EXISTS(
SELECT 1
FROM c
WHERE c.a_id = a.id
)
Note, that there is no need to join table b as the existence of the row in c always guarantees for the row in b and you do not need any information contained in this row/table.
Perhaps even more clean might be:
SELECT DISTINCT
a.* -- or whatever columns you need of a
FROM a
LEFT JOIN c
You can have a look at the query plans and execution times using EXPLAIN ANALYZE <query>. Perhaps this gives you a hint on what to use best.
But be aware of caching, repeat both queries multiple times this way to see comparable results.

Oracle SQL: Get all users in one table but not another and join to a third table

I am wondering how to use oracle sql to get all the rows that are in one table but not another. The issue I am having is that the two tables don't have a field in common so I need to join to a third master table.
This is what I've tried which doesn't produce any errors but also produces 0 records which isn't possible but clearly I've done something wrong.
SELECT a.USER_ID, c.AD_ID, c.CREATED_DATE_ FROM $A$ a, $C$ c, $B$ b
WHERE (b.USER_ID IS NULL AND a.CUSTOMER_ID = c.CUSTOMER_ID)
I have three tables:
Table A has fields CUSTOMER_ID & USER_ID
Table B has field USER_ID
Table C has field CUSTOMER_ID
I need all the users that are in table C but not table B. They are all in Table A because that is the master list of users.
Any insight would be greatly appreciated.
SELECT
*
FROM
table_a
WHERE
NOT EXISTS (SELECT * FROM table_b WHERE table_b.user_id = table_a.user_id )
AND EXISTS (SELECT * FROM table_c WHERE table_c.customer_id = table_a.customer_id)
My solution:
select * from TableC tc
join TableA ta on tc.CUSTOMER_ID=ta.CUSTOMER_ID
left join TableB tb on tb.USER_ID=ta.USER_ID
where ta.USER_ID is null
I think you want:
select a.USER_ID, c.AD_ID, c.CREATED_DATE_
from a join
c
on a.customer_id = c.customer_id
where not exists (select 1 from b where b.user_id = a.user_id);

Oracle SQL WITH clause select joined column

SQL:
WITH joined AS (
SELECT *
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
returns invalid identifier.
How can you select joined column when using WITH clause? I have tried aliases, prefixing and nothing worked. I know I can use:
WITH joined AS (
SELECT a.a_id
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
but I need this alias to cover all fields.
Only way I managed to meet this condition is using:
WITH joined AS (
SELECT a.a_id a_id_alias, a.*, b.*
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id_alias
FROM joined
but it is not perfect solution...
You can use the effect of the USING clause when joining the tables.
When you join tables where the join columns have the same name (as it is the case with your example), the USING clause will return the join column only once, so the following works:
with joined as (
select *
from table_a a
join table_b b using (a_id)
)
select a_id
from joined;
SQLFiddle example: http://sqlfiddle.com/#!4/e7e099/2
I don't think you can do this without aliases. The result of the "joined" query has two fields, both named a_id. Unless you alias one (or both), as you did in your final query, the outer query has no idea which a_id you are referring to.
Why is your final query not a "perfect" solution?
You can probably use alias as below:
WITH JOINED AS (
SELECT A.A_ID A_A_ID, B.A_ID B_A_ID,
A.FIELD_NAME1 A_FIELDNAME1, A.FIELDNAME2 A_FIELDNAME2,A.FIELDNAME_N A_FIELDNAME_N,
B.FIELD_NAME1 B_FIELDNAME1, B.FIELDNAME2 B_FIELDNAME2,B.FIELDNAME_N B_FIELDNAME_N,
FROM TABLE_A A
JOIN TABLE_B B ON (A.A_ID = B.A_ID)
)
SELECT A_A_ID, B_A_ID
FROM JOINED
IT IS ALWAYS A GOOD PRACTICE TO AVOID USING SELECT *

Can this be done with a single SQL Join?

I am not sure if this can be done with a single JOIN, but I basically have two tables with an ID column in common. To make it simple I'll say Table A just contains an ID while Table B contains an ID and Code. There is a 1:M relationship between Table A and Table B, however it's also possible an ID from Table A is not contained in Table B at all. I was hoping to have a query return every ID that exists in Table B within a particular code range, or does not exist in Table B at all.
I tried using a LEFT JOIN with something like:
SELECT A.id FROM A LEFT JOIN B ON A.id = B.id AND b.code BETWEEN '000' AND '123'
But, this still gives me the IDs that exist in Table B outside of the code range.
Use a left join, and filter the result to contain the codes in the range, and also the lines where there is no matching record in table B:
select
A.id
from
A
left join B on B.id = A.id
where
B.code between '000' and '123' or B.id is null
What about
SELECT id FROM A LEFT JOIN B ON A.id = B.id
WHERE b.code IS NULL OR b.code BETWEEN ' ' AND '123'

The Difference Inner Join Query

I'm just curious, if i have table a and table b.
I write query 1:
SELECT * FROM table a INNER JOIN table b ON table a.id = table b.id
I write query 2:
SELECT * FROM table b INNER JOIN table a ON table b.id = table a. id
What is the difference both of above query?
Thank you
When using INNER JOIN , there is no difference in resultset returned except in order of columns when SELECT * is used i.e. columns are not explicitly mentioned.
SELECT *
FROM table a
INNER JOIN table b
ON table a.id = table b.id
returns columns from tableA followed by columns from tableB
SELECT *
FROM table b
INNER JOIN table a
ON table b.id = table a. id
returns columns from tableB followed by columns from tableA
The second table matches data with the first one.
So it is better to put smaller table on the second place.