Two right joins - mysql

I am trying to select all records in TABLEC and its equivalent value in TABLEA or TABLEB using right join. I am using MYSQL 5.5.47.
--Table data as follows
TABLEA TABLEB TABLEC
ID FNAME ID MNAME ID LNAME
0 ANOOP 0 N 0 SINGH
1 BIMA 2 SITA 3 RAJ
4 CIMI 4 B 5 KUMAR
6 RAVI 5 A 6 D
--Using below query and trying to select all records in TABLEC and its equivalent value in TABLEA or TABLEB
SELECT A.FNAME, B.MNAME, C.LNAME
FROM TABLEA AS A
RIGHT JOIN TABLEB AS B ON A.ID = B.ID
RIGHT JOIN TABLEC AS C ON C.ID = B.ID
--I am getting the following result
ANOOP N SINGH
NULL NULL RAJ
NULL A KUMAR
***NULL*** NULL D
The highlighted value doesn’t show the value as 'RAVI' instead it shows NULL in MYSQL 5.5.47. I tried to modify the '=' condition in second join related to C & A but still no luck. What am I doing wrong here? How do I get the value 'RAVI' in place of NULL? Any suggestion would be highly helpful.

DROP TABLE IF EXISTS table_a;
DROP TABLE IF EXISTS table_b;
DROP TABLE IF EXISTS table_c;
CREATE TABLE table_a
(id INT NOT NULL PRIMARY KEY
,fname VARCHAR(12) NULL
);
INSERT INTO table_a VALUES
(0,'ANOOP'),
(1,'BIMA'),
(4,'CIMI'),
(6,'RAVI');
CREATE TABLE table_b
(id INT NOT NULL PRIMARY KEY
,mname VARCHAR(12) NULL
);
INSERT INTO table_b VALUES
(0,'N'),
(2,'SITA'),
(4,'B'),
(5,'A');
CREATE TABLE table_c
(id INT NOT NULL PRIMARY KEY
,lname VARCHAR(12) NULL
);
INSERT INTO table_c VALUES
(0,'SINGH'),
(3,'RAJ'),
(5,'KUMAR'),
(6,'D');
SELECT a.fname
, b.mname
, c.lname
FROM table_c c
LEFT
JOIN table_a a
ON a.id = c.id
LEFT
JOIN table_b b
ON b.id = c.id;
+-------+-------+-------+
| fname | mname | lname |
+-------+-------+-------+
| ANOOP | N | SINGH |
| NULL | NULL | RAJ |
| NULL | A | KUMAR |
| RAVI | NULL | D |
+-------+-------+-------+
4 rows in set (0.02 sec)

You are trying to select all records in TABLEC and its equivalent value in TABLEA or TABLEB using right join. So Table A and B is joined to Table c records. So we need to use Left join(you will get all records of Table C and common records of Table A and B). More info please ref this link
SELECT
ifnull(A.FNAME,""),
ifnull(B.MNAME,""),
ifnull(C.LNAME,"")
FROM
TABLEA AS A
LEFT JOIN
TABLEB AS B
ON
A.ID = B.ID
LEFT JOIN
TABLEC AS C
ON
C.ID = B.ID

The problem is you don't have a table that contains all the ids. So you have to make one. Then you can join from that.
Get all the ids with this query
SELECT ID FROM TABLEA
UNION
SELECT ID FROM TABLEB
UNION
SELECT ID FROM TABLEC
Now we can use this query/table of ids to join the others
SELECT A.FNAME, B.MNAME, C.LNAME
FROM (
SELECT ID FROM TABLEA
UNION
SELECT ID FROM TABLEB
UNION
SELECT ID FROM TABLEC
) I
LEFT JOIN TABLEA A ON I.ID = A.ID
LEFT JOIN TABLEB B ON I.ID = B.ID
LEFT JOIN TABLEC C ON I.ID = C.ID
Of course if you had another table (TABLEID) that had a list of all IDs you could use that instead of the sub-query above. It might be your model has such a table, but we won't know unless you tell us.

As you said "select all records in TABLEC and its equivalent value in TABLEA or TABLEB", so you need to join the C with A and C with B. So your need to update your query as :
SELECT A.FNAME, B.MNAME, C.LNAME
FROM TABLEC AS C RIGHT JOIN TABLEB AS B
ON B.ID = C.ID
RIGHT JOIN TABLEA AS A
ON C.ID = A.ID
If you want all the record that exist in A, B and C. The NULL value will shown for the record which doesn't have the value,
SELECT A.FNAME, B.MNAME, C.LNAME
FROM (
TABLEA AS A
LEFT JOIN TABLEB AS B ON B.ID = A.ID
)
RIGHT JOIN TABLEC AS C ON ( C.ID = B.ID
OR B.ID = NULL
OR A.ID = C.ID )
WHERE 1

Use this works perfectly
SELECT A.FNAME, B.MNAME, C.LNAME
FROM TABLEC AS C
LEFT JOIN TABLEA AS A ON (A.ID = C.ID)
LEFT JOIN TABLEB AS B ON (B.ID = C.ID)

Related

Fetch data from three tables where a particular column from other two tables are null?

I have three tables: A, B and C.
Tables have the following columns:
A: id, name, shipdate
B: id, returndate
C: id, deliverydate
I have fetched data of Tables A and B using INNER JOIN and the ID Column.
SELECT A.name,
A.shipdate,
B.returndate
FROM A INNER JOIN B ON A.id = B.id
Same I have fetched data of Tables A nd C using INNER JOIN AND ID column.
But how to fetch data from Tables A, B and C where returndate is null and deliverydate is null?
Here's the query i tried:
SELECT A.name,
A.shipdate,
B.returndate,
C.deliverydate
FROM A
INNER JOIN B ON A.id = B.id
INNER JOIN C ON A.id = C.id
WHERE B.returndate = null
AND C.deliverydate = null
Just constrain your condition in WHERE:
SELECT A.*
FROM A
INNER JOIN B
ON A.id = B.id
INNER JOIN C
ON B.id = C.id
WHERE
ISNULL(B.returndate) = 1 AND ISNULL(C.deliverydate) = 1
Instead of ISNULL(B.returndate) = 1 you can use B.returndate is null, but a statement like B.returndate = null will always return false.
Using left join and IS NULL (= null won't find anything since null is <> to anything)
drop table if exists a,b,c;
create table a(id int, name varchar(3), shipdate date);
create table b(id int,returndate date);
create table c(id int,deliverydate date);
insert into a values(1,'aaa','2022-01-01'),(2,'bbb','2022-01-01'),(3,'ccc','2022-01-01'),(4,'ddd','2022-01-01');
insert into b values(1,'2022-01-01'),(2,'2022-01-01');
insert into c values(1,'2022-01-01'),(3,'2022-01-01');
SELECT A.name, A.shipdate, B.returndate, C.deliverydate
FROM A
left JOIN B ON A.id = B.id
left JOIN C ON A.id = C.id
WHERE B.returndate is null AND C.deliverydate is null;
+------+------------+------------+--------------+
| name | shipdate | returndate | deliverydate |
+------+------------+------------+--------------+
| ddd | 2022-01-01 | NULL | NULL |
+------+------------+------------+--------------+
1 row in set (0.001 sec)

SQL count rows in third table

A row in Table A can be linked to many rows in Table B. A row in Table B will be linked to either one or zero rows in Table C.
For a given row in Table A, I would like to count the (indirectly) linked rows in Table C.
I would like to return this for each row in Table A. The below doesn't give any errors, but doesn't give the correct value.
SELECT
*,
(
SELECT count(*)
FROM TABLE_A
INNER JOIN TABLE_B ON TABLE_A.id = TABLE_B.foreignKeyA
INNER JOIN TABLE_C ON TABLE_B.id = TABLE_C.foreignKeyB
) as cCount
FROM TABLE_A
Sample data:
TABLE_A
id
1
2
TABLE_B
id foreignKeyA
1 1
2 1
3 2
4 2
TABLE_C
id foreignKeyB
1 3
2 4
Should return (for the rows of Table A):
id cCount
1 0
2 2
I would suggest a correlated subquery:
SELECT a.*,
(SELECT count(*)
FROM TABLE_B b JOIN
TABLE_C c
ON c.foreignKeyB = b.id
WHERE b.foreignKeyA = a.id
) as aCount
FROM TABLE_A a;
Obviously, if you want the count for each row in TABLE_C, then you would adjust the table names and conditions.
You can do this with JOINs, but you need outer joins and an overall aggregation.
> with table_count as (
Select count(*) as cnt, TableB_FK
From TableB B
JOIN TableA A on A.FK = B.FK
Group By B.FK
)
select C.*, nvl(t.cnt,0)
from TableC C
left join table_count T on T.tableB_fk = C.FK
Table_count has aggregate count for foreign Keys.
Left Join table C with table count and replace null with 0
Change the INNER joins to LEFT joins for the case there are not any linked rows to TABLE_C, in which case you want 0 as result:
SELECT TABLE_A.id, count(TABLE_C.id) cCount
FROM TABLE_A
LEFT JOIN TABLE_B ON TABLE_B.foreignKeyA = TABLE_A.id
LEFT JOIN TABLE_C ON TABLE_C.foreignKeyB = TABLE_B.id
GROUP BY TABLE_A.id
See the demo.
Results:
| id | cCount |
| --- | ------ |
| 1 | 0 |
| 2 | 2 |

MySQL: join 3 tables and select an identical row as alias

I want to join 3 tables in something like the following manner:
SELECT a.id
FROM tableA AS a
LEFT JOIN tableB AS b ON a.id = b.id
LEFT JOIN tableC AS c ON a.id = c.id
WHERE
b.name = c.name OR b.name IS NULL OR c.name IS NULL;
I can't be sure, that table b or c will have a row to join, but if both have a row to join, the name column must be identical.
My question is: I want to select this name column, but I only want to select it once. So, if b and c have a row to join, I want the name from either of them, If just one has a row to join, I want the name of that row.
The column name in the result should be in each case identical.
Table examples
tableA
id
----
1
2
3
4
tableB
id | name
----|------
2 | X
3 | Y
tableC
id | name
----|------
2 | Q
3 | Y
4 | Z
desired result:
id | name
----|------
1 | (NULL)
2 | X (name is from tableB)
2 | Q (name is from tableC)
3 | Y (name is from tableB or tableC)
4 | Z (name is from tableC)
I hope this will help you
SELECT
a.id,
(CASE COALESCE(b.`name`, '') WHEN '' THEN c.`name` ELSE b.`name` END) AS name2,
b.`name` AS B,
c.`name` AS C
FROM foo1 AS a
LEFT JOIN foo2 AS b ON (a.id = b.id)
LEFT JOIN foo3 AS c ON (a.id = c.id)
ORDER BY a.id;
SELECT a.id, IFNULL(b.name, c.name)
FROM tableA AS a
LEFT JOIN tableB AS b ON a.id = b.id
LEFT JOIN tableC AS c ON a.id = c.id
WHERE
b.name = c.name OR b.name IS NULL OR c.name IS NULL;
This query should return what you want. IFNULL(X, Y) works by saying if X is null, then use Y. With your example, if b.name is not null, b.name will be shown. If b.name is null, then c.name will be shown. If something is in c.name, then the name will be printed, but if c.name is null NULL will be shown as you desired.
Another possibility, would be best to get rid of LEFT at all, if not necessary.
SELECT a.id, b.name
FROM tableA AS a
LEFT JOIN tableB AS b ON a.id = b.id
UNION
SELECT a.id, c.name
FROM tableA AS a
LEFT JOIN tableC AS c ON a.id = c.id
if you don't want the rows where name is NULL, remove LEFT

Counting all childs and sub-childs of each node in a hierarchy

I have this hierarchy of tables :
Table A
|
| Table B
|
| Table C
|
| Table D
For a given row in Table A, let's say the row with ID=1, I want to get this output :
ID | childB | ChildC | childD
-------------------------------
1 | x | x | x
Where childB is the number of children in Table B, ChildC are the children in Table C of the children found in Table B..., etc.
I want to get this output by one sql query. Now I can get only the counting of the children in Table B using this query :
SELECT a.ID, (SELECT
COUNT(b.parentID)
FROM TableB AS b
WHERE b.parentID= a.ID)
AS childB
FROM TableA a
WHERE a.ID =1
if you want it for a specific ID (as you mentioned for example ID=1) you can left join them all on idparent and id and use count(distinct):
select a.ID,
count(distinct b.id) childB,
count(distinct c.id) childC,
count(distinct d.id) childD
from tableA a
left join tableB b on b.parentID = a.ID
left join tableC c on c.parentID = b.ID
left join tableD d on d.parentID = c.ID
where a.ID=1
group by a.ID;
here is a fiddle DEMO.

MySQL Multiple JOIN query

I have 3 tables:
Table A:
id int
value varchar
Table B:
id int
a_id default null
Table C:
id int
a_id not null
And I need to group number of B rows and C rows by A.value:
+---------+----------------------+----------------------+
| A.value | COUNT(DISTINCT B.id) | COUNT(DISTINCT C.id) |
+---------+----------------------+----------------------+
| NULL | 100 | 0 |
| 1 | 543 | 324 |
...
The problem is that the B table has a nullable foreign key while C.a_id can not be null.
So after hour of trying I can't get the right query. Either C.a_id are losing or B.a_id.
What is the right way to get it?
Because the values are pretty large, it might be better to do the calculations in subqueries:
select a.name, Distinct_B, Distinct_C
from (select distinct a.name from TableA a) a left outer join
(select a.value, count(distinct b.id) as Distinct_B
from TableA a join
TableB b
on a.id = b.a_id
group by a.value
) b
on a.value = b.value left outer join
(select a.value, count(distinct c.id) as distinct_C
from TableA a join
TableC c
on a.id = c.a_id
) c
on a.value = c.value
This looks more complicated, but it does not require a partial cartesian product within each a.value. Also, it can be simplified, if there are no multiple a.values allowed.
If you want to keep all B values that have "NULL" a_id by assigning them a NULL a.value, then use this subquery instead:
select a.value, sum(Distinct_B), sum(Distinct_C)
from ((select distinct a.name, 0 as Distinct_B, 0 as Distinct_C
from TableA a
) union all
(select a.value, count(distinct b.id) as Distinct_B, 0 as Distinct_C
from TableB b left outer join
TableA a
on a.id = b.a_id
group by a.value
) union all
(select a.value, 0 as Distinct_B, count(distinct c.id) as distinct_C
from TableC c left outer join
TableA a
on a.id = c.a_id
)
) t
group by a.value
This uses aggregation instead of a join to bring the values together.