How do I run the following query? - sql

I have to table A and B.
The relationship is one to many.
In table B have foreign key from A.
TABLE A:
... fields
TABLE B:
f = foreignkey(A)
How to get all A without B ?
The query below is not working.
select TABLE_A.id, COUNT(TABLE_B.f)
from TABLE_A JOIN TABLE_B
ON (TABLE_A.id = TABLE_B.f)
GROUP BY TABLE_A.id HAVING COUNT(TABLE_B.f) = 0;

Use not exists?
select a.*
from table_a a
where not exists (select 1
from table_b b
where a.id = b.f
);
Or not in. Or left join with where.

Change JOIN to LEFT JOIN :
TABLE_A.id, COUNT(TABLE_B.f)
from TABLE_A
LEFT JOIN TABLE_B ON (TABLE_A.id = TABLE_B.f)
GROUP BY TABLE_A.id
HAVING COUNT(TABLE_B.f) = 0;

You can do a LEFT JOIN and take only the rows that have NULL in the column TABLE_B.f,
meaning that there is no TABLE_B.f to match TABLE_A.id:
SELECT TABLE_A.id
FROM TABLE_A LEFT JOIN TABLE_B
ON TABLE_A.id = TABLE_B.f
WHERE TABLE_B.f IS NULL;
assuming that TABLE_A.id is unique in TABLE_A,
otherwise use
SELECT DISTINCT TABLE_A.id

You can use the left join and check the nullity on right table.
SELECT TABLE_A.id,count(*)
FROM TABLE_A LEFT JOIN TABLE_B
ON TABLE_A.id = TABLE_B.f
WHERE TABLE_B.f IS NULL
group by TABLE_A.id;

Related

Postgress how to query with not in for multiple column

I want to select from table C all items ID where column A "item_a_id" and column B "item_b_id" not in result of another query.
currently I use this query twice , i didnt find a way how to query it without the using same query twice.
This is my query:
SELECT * from table_c c
WHERE c.item_a_id NOT IN
(
SELECT a.item_id,b.item_id
FROM table_a a
JOIN table_b b on a.item_id = b.item_id
)
AND c.item_b_id NOT IN
(
SELECT a.item_id,b.item_id
FROM table_a a
JOIN table_b b on a.item_id = b.item_id
)
and this is how I want to improve it (ofc this is not sql syntax and just an example)
SELECT * from table_c c
WHERE c.item_a_id AND c.item_b_id NOT IN
(
SELECT a.item_id,b.item_id
FROM table_a a
JOIN table_b b on a.item_id = b.item_id
)
You need to enclose the columns on the left hand side in parentheses:
WHERE (c.item_a_id, c.item_b_id)
NOT IN (SELECT a.item_id,b.item_id
FROM table_a a
JOIN table_b b on a.item_id = b.item_id)
But typically NOT EXISTS conditions are faster than NOT IN
WHERE NOT EXISTS (SELECT *
FROM table_a a
JOIN table_b b on a.item_id = b.item_id
WHERE a.item_id = c.item_a_id
AND b.item_id = c.item_b_id)
If I understand correctly, you should be able to just do two consecutive left joins to the A and B tables. A valid match, then, is one for which neither table has any join match.
SELECT *
FROM table_c c
LEFT JOIN table_a a
ON c.item_a_id = a.item_id
LEFT JOIN table_b b
ON c.item_b_id = b.item_id
WHERE
a.item_id IS NULL AND
b.item_id IS NULL;
By the way, the above query is specifically called a left anti-join.

How can I join 4 tables

Please help to modify the below code. I want to join these two select queries such that I can get a single output with records from two diff tables ? I have 4 tables,
table_a has the user id that I have to use to search
table_b1 has the foreign key for table_c which has the name that I want to get
table_b2 also has the foreign key for table_c which has the second name that I want to get too.
How can I combine below query in a single output?
my code
select c.name from table_a a
join table_b1 b1 on a.id=b1.id
join table_c c on b1.pri_id=c.id where a.user='abc'
select c.name from table_a a
join table_b2 b2 on a.id=b2.id
join table_c c on b2.pri_id=c.id where a.user='abc'
So you want to extract the names information in table_c for tables table_b1 and table_b2, which also join to table_a by the id column.
You'll need to add table_c twice to your query to retrieve name from table_b1 and name from table_b2, because the conditions to retrieve the name are different.
If you only want names when there is information in table_b1 AND table_b2 (and in table_c for each of the b tables), the query will be:
SELECT tc1.name name_b1, tc2.name name_b2
FROM table_a ta
JOIN table_b1 tb1 ON ta.id = tb1.id
JOIN table_b2 tb2 ON ta.id = tb2.id
JOIN table_c tc1 ON tb1.pri_id = tc1.id
JOIN table_c tc2 ON tb2.pri_id = tc2.id
WHERE ta.user = 'abc'
If there might not always be information for user in table_b1 or table_b2, but you want to retrieve information anyway, getting NULL when there isn't a name on one or both of the b tables, you'll need left joins:
SELECT tc1.name name_b1, tc2.name name_b2
FROM table_a ta
LEFT JOIN table_b1 tb1 ON ta.id = tb1.id
LEFT JOIN table_b2 tb2 ON ta.id = tb2.id
LEFT JOIN table_c tc1 ON tb1.pri_id = tc1.id
LEFT JOIN table_c tc2 ON tb2.pri_id = tc2.id
WHERE ta.user = 'abc'
May be you can use UnionAll here like this,
select c.name from table_a a
join table_b1 b1 on a.id=b1.id
join table_c c on b1.pri_id=c.id where a.user='abc'
union all
select c.name from table_a a
join table_b2 b2 on a.id=b2.id
join table_c c on b2.pri_id=c.id where a.user='abc'

If a row does not exist, check a second column on a join

I'm trying to join a table on a column
Select * From tableA a
LEFT JOIN tableB b
ON a.key = b.foreignkey
...
If that row cannot be found I want to join it to another column in table B. Is there an efficient way to do this.
Thanks
You can use COALESCE to join on the first non-NULL column.
Select * From tableA a
LEFT JOIN tableB b
ON a.key = COALESCE(b.foreignkey, b.another_column, b.another_column2)
It will try to join with b.foreignkey first. if that is NULL then b.foreignkey and so on.
Please find the example here.
Add another LEFT JOIN:
Select *
From tableA a left join
tableB b
on a.key = b.foreignkey left join
tableC c
on a.key = c.foreignkey and b.foreignkey is null;

Is subtraction of inner join from full outer join some type of "join"?

Given two tables, is there a name for the result of subtracting inner join from full outer join, both on the same condition? Is it a type of "join"? Thanks.
It is not a type of join in SQL. You can write it as:
select . . .
from a full join
b
on a.id = b.id
where a.id is null or b.id is null;
If you are looking for ids that are in only one table, it can be more efficient to do:
select a.id
from a
where not exists (select 1 from b where b.id = a.id)
union all
select b.id
from b
where not exists (select 1 from a where a.id = b.id);

Controlling join order in combining left join and inner join in Impala SQL

With this kind of data
create table table_a as select 1 as id1;
insert into table_a values (2),(3);
create table table_b as select 1 as id1, 'a' as id2;
insert into table_b values (1,'b');
create table table_c as select 'a' as id2;
I have the following kind of join in Impala sql:
select *
from table_a as a
left join table_b as b
on b.id1 = a.id1
left join table_c as c
on c.id2 = b.id2
yielding this result
"id1","id1","id2","id2"
1,1,b,
1,1,a,a
2,,,
3,,,
I would like the second join to be inner join instead of left join:
select *
from table_a as a
left join table_b as b
on b.id1 = a.id1
join table_c as c /* <- How to process this join first without using inner queries? */
on c.id2 = b.id2
and get this result:
"id1","id1","id2","id2"
1,1,a,a
2,,,
3,,,
Thus, I would like the inner join of table_b and table_c to take place first and only after to do the left join between table_a and (table_b inner joined to table_b).
Is possible to determine the join order in such manner without using inner queries?
With the help from #jarlh, I realized left-to-right processing of joins and then found that it is possible to use RIGHT joins:
select *
from table_c as c
join table_b as b
on b.id2 = c.id2
right join table_a as a
on a.id1 = b.id1;
in order to get the desired result:
"id2","id1","id2","id1"
a,1,a,1
,,,2
,,,3