Compare table one value with two different tables in postgresql - sql

There are three tables, A,B and C having common columns(name and number)
Table A have 10 records(say x) which can be only from table B(say, y) and table C(say, z) (like, x = y+z).
In table A, there are some records whose value is 0 (zero)
I need to compare those zero value based records using column = name, with other two tables.
And check the column "number" for the same "name" is also zero (0) in table B and table C?
I tried to write the below sample query to test on my small set of 3 tables data- but for some reasons I am not able to get all the 10 records as a result?
SELECT a.name,a.number as A_number, b.number as B_number, c.number as C_number
from A a, B b, C c
WHERE a.name = b.name
The above query gives me data as follows in the sqlfiddle-
http://sqlfiddle.com/#!2/57f86/1
In the above data- theres no record name="hello"
Can anyone please correct me where I am going wrong? and how to get the exact result? I need all the records from Table A. I know if I use left join it will populate all the left table data even if no match.
Possibilities: Table A having records, some may be present in table B
and some in table C, but not on both.

I think this is what you want:
SELECT a.*, b.number as bnumber, c.number as cnumber
from a left outer join
b
on a.name = b.name left outer join
c
on a.name = c.name
where a.number = 0;
By the way, here is a Postgres SQL Fiddle.

It's been over 20 years since the JOIN keyword was added to SQL. Use it:
select
a.name,
a.number as A_number,
b.number as B_number,
c.number as C_number
from A a
left join B b on a.name = b.name
left join C c on a.name = c.name
where a.number = 0
The key here is the use of left join, which allows all rows in table A to be returned, even if there are no matching rows in the other tables.
If you want to just display true/false if the number is zero in the other tables, do this:
select
a.name,
a.number as A_number,
(b.number = 0 and c.number = 0) as zero_elsewhere
from A a
left join B b on a.name = b.name
left join C c on a.name = c.name
where a.number = 0

When you wrote WHERE a.name = b.name, that restricted the records returned from table A to only those that also exist in table B. This is not equivalent to a left join. If you used only a WHERE statement you would need to do:
WHERE ((a.name = b.name) OR (b.name is NULL))
AND
((a.name = c.name) OR (c.name is NULL))
In the comments and other answers, they have been using LEFT JOIN which is easier to write and read. I suggest you adopt that style as it is widely accepted.

Related

Subqueries vs Multi Table Join

I've 3 tables A, B, C. I want to list the intersection count.
Way 1:-
select count(id) from A a join B b on a.id = b.id join C c on B.id = C.id;
Result Count - X
Way 2:-
SELECT count(id) FROM A WHERE id IN (SELECT id FROM B WHERE id IN (SELECT id FROM C));
Result Count - Y
The result count in each of the query is different. What exactly is wrong?
A JOIN can multiply the number of rows as well as filtering out rows.
In this case, the second count should be the correct one because nothing is double counted -- assuming id is unique in a. If not, it needs count(distinct a.id).
The equivalent using JOIN would use COUNT(DISTINCT):
select count(distinct a.id)
from A a join
B b
on a.id = b.id join
C c
on B.id = C.id;
I mention this for completeness but do not recommend this approach. Multiplying the number of rows just to remove them using distinct is inefficient.
In many databases, the most efficient method might be:
select count(*)
from a
where exists (select 1 from b where b.id = a.id) and
exists (select 1 from c where c.id = a.id);
Note: This assumes there are indexes on the id columns and that id is unique in a.

Outer join not showing extra entries

I have made a query in which 3 tables are used. The first table has all the desired names which I need. The 2nd and 3rd table give me those names on which there is some bill amount. But I need all the names from the 1st table as well.
SELECT a.name,
nvl(c.bill_amount,0)
FROM table_1 a left outer join table_2 b
ON a.name = b.name
left outer join table_3 c on B.phone_number = C.phone_number
AND B.email = C.email
where b.status = 'YES'
and a.VALID = 'Y';
Now, the tables b and c give me limited number of names, lets say 5 on which bill is there. But in table_1, there are 10 names. I want to display them also with 0 bill_amount on their name. I'm using Oracle.
Applying a where clause on the right hand tale basiically makes it an inner join. To keep it OUTER, put the condition in the join conditions
Try:
SELECT a.name,
nvl(c.bill_amount,0)
FROM table_1 a
left outer join table_2 b
ON a.name = b.name
and b.status = 'YES' -- Put it here
left outer join table_3 c
on B.phone_number = C.phone_number
AND B.email = C.email
where a.VALID = 'Y'; -- Only items from the left hand table should go in the where clause
The answer above is right , I would just want to be more precise. The fact is when a left join does not match, the column of the right hand table are set to NULL.
Actually NULL is always propagating value in SQL, so b.status = 'YES' have the value NULL if the join does not math, and then the predicate does not match neither.
The general way to handle this would be (b.status = 'YES' or b.name IS NULL) : because b.name is the join column it is null if and only if join does not match, which may not be the case for b.status.
Because NULL is propagating you cannot use field = NULL but field IS NULL instead.
But it is okay to have it in the join clause when it is more clear.

display Count of one column from another table even when the count is zero

I have two tables A and B. In Table A (Oracle sql), an unique column(not primary key) code may have some records in table B.
Example:
Code "A" has 3 entries, Code "B" has 2 entries and code "C" has 0 entries in table B. I want the query to display the code and its count of records in Table B.
A 3
B 2
C 0,
But i am not getting the code with zero records in table B, i.e C 0.
Please anyone can help me with the query.
GROUP BY with LEFT JOIN solution:
select a.code,
a.name,
count(b.code)
from A a
LEFT JOIN B b ON a.code = b.code
group by a.code, a.name
Correlated sub-query solution:
select a.code,
a.name,
(select count(*) from B b where a.code = b.code)
from A a
Perhaps you need to do SELECT DISTINCT here.
You are doing something incorrectly. This works for me:
select A.code, Count(B.code) from A
left join B on A.code = b.code
group by A.code
Fiddle: http://sqlfiddle.com/#!4/f13e1/2
It is quite easy, you just need to Take column base on you want count as I did "A.code" and don't forget to Group by that column, and use COUNT().
Check the below solution
select A.code, Count(B.code) AS Count
from A
left join B on A.code = b.code
group by A.code

Sql Subquery result

I have 3 tables, A, B,C
Table A,Columns: latlong, name
Table B, columns : code, name
Table C, Columns : latlong, code
I want to update table A,column Name with the values from Table B, Column Name, something like:
update A set A.name =
(select b.name
from B where code = c.code)
where a.latlong = c.latlong
Note that all the columns are not related.
Would appreciate the right direction to go about it.
Have tried Sub queries with inner joins, but no good.
You can do this with an update using join:
update a
set name = b.name
from a join
c
on c.latlong = a.latlong join
b
on b.code = c.code;
Try update with INNER JOIN
update A set
A.name = B.name
FROM A
INNER JOIN C on C.latlong = A.latlong
INNER JOIN B on B.code = C.code
You have mentioned in your question the following:
I want to update table A,column Name with the values from Table B, Column Name
But what I can see from your query is that actually , you need only those values of the column Name of table B which has same value of code as in table C, and that your latlong in A should be the same as latlong in C, if I'm not mistaken.
Based on that, I can say you need an SQL JOIN operation for Tables B and C with table A. Something like this:
UPDATE A SET A.name = B.Name
FROM A
JOIN C
ON C.latlong = A.latlong
JOIN B
ON B.code = C.code
No need to create a SUBQUERY
Last condition is missing where Table A.Latlong = C.Latlong to pick up the correct code!

ORACLE/SQL - Joining 3 tables that aren't all interconnected

I need help joining 3 tables where they are not all interconnected
So lets say I have tables A, B, C
here are the relations
A.type = B.type
A.model = C.model
What I need to do is inner join A and B and return all the matched A records. Next I need to pull the records from C that match on the prior join.
Or in other words all the records in C that are in A where A is in B
Hope that makes sense. Sorry for no data examples.
I have tried this
select
c.*
from
c, a, b
where
c.model_ = a.model_
and a.type_ = b.type_
but receive this message 'Errors: Query has MERGE JOIN CARTESIAN. You must correct where-clause to properly join tables in the select statement.'
I know this is a matter of style but in my opinion ansi style joins make this much clearer:
SELECT c.*
FROM c
JOIN a ON a.model = c.model
JOIN b on b.type = a.type
In case you have multiple matching elements in a or b, this query will return duplicates. You can either add a DISTINCT or rewrite it as an EXISTS query:
SELECT *
FROM c
WHERE EXISTS (SELECT 1
FROM a
JOIN b ON b.type = a.type
WHERE a.model = c.model)
I think this should also give the same result, as long as there are no NULL values in model:
SELECT *
FROM c
WHERE c.model IN (SELECT a.model
FROM a
JOIN b ON b.type = a.type)
simply also join to C with an AND condition
Without the data samples, it is difficult to understand the actual problem and validate the query.
did you try..
Select c.*
from a,b,c
where a.type = b.type
and a.model = c.model;
Are your losing some records or seeing extra records that you don't expect to see?
The above query will only give you records in c that are in a and where a records match the criterion in b.