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.
Related
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 |
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
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)
I have 3 tables:
table a => id, name
table b => id, id_a, amount
table c => id, id_a, amount
How can I select table a and the total amount from table b, and table c?
I already have tried:
SELECT a.`name`, SUM(b.`amount`) AS Total
FROM a
LEFT JOIN b ON a.`id` = b.`id_a`
UNION
SELECT a.`name`, SUM(c.`amount`) AS Total
FROM a
RIGHT JOIN c ON a.`id` = c.`id_a`
GROUP BY a.`id`
But it shows multiple records from table a where there is id_a value in both table b and table c.
FYI: if table a is inserted, so table b or table c or both table b and table c will be inserted the detail. So there is no possible table a has no detail in table a or table b
here is the example data
table a:
id | name
1 | name 1
2 | name 2
table b:
id | id_a | amount
1 | 1 | 300
2 | 1 | 200
table c:
id | id_a | amount
1 | 1 | 200
2 | 1 | 100
3 | 2 | 300
4 | 2 | 100
Preferred Result:
name | amount
name 1 | 800
name 2 | 400
UPDATE THE ANSWER => Thanks to #Jens
SELECT d.NAME, SUM(d.Total) FROM (
SELECT a.id AS id , a.`name` AS NAME, SUM(b.`amount`) AS Total
FROM a
LEFT JOIN b ON a.`id` = b.`id_a`
GROUP BY a.`id`
UNION
SELECT a.`id` AS id, a.`name`, SUM(c.`amount`) AS Total
FROM a
RIGHT JOIN c ON a.`id` = c.`id_a`
GROUP BY a.`id`
) AS d
GROUP BY d.`id`
ANOTHER ANSWER FROM #Alex IS WORKING TOO AND SIMPLER
Thanks to both #Jens and #Alex. It's increase my knowledge
Try
select d.name, sum(d.total) from (
SELECT a.id as id , a.`name` as name, b.`amount` AS Total
FROM a
LEFT JOIN b ON a.`id` = b.`id_a`
UNION
SELECT a.id as id a.`name`, c.`amount` AS Total
FROM a
RIGHT JOIN c ON a.`id` = c.`id_a`
) as d
GROUP BY d.`id`
UPDATED:
SELECT d.NAME, SUM(d.Total) FROM (
SELECT a.id AS id , a.`name` AS NAME, SUM(b.`amount`) AS Total
FROM a
LEFT JOIN b ON a.`id` = b.`id_a`
GROUP BY a.`id`
UNION
SELECT a.`id` AS id, a.`name`, SUM(c.`amount`) AS Total
FROM a
RIGHT JOIN c ON a.`id` = c.`id_a`
GROUP BY a.`id`
) AS d
GROUP BY d.`id`
Have you tried this?
SELECT a.name, sum(b.amount), sum(c.amount)
FROM a
JOIN b on a.id = b.id_a
JOIN c on a.id = c.id_a
GROUP BY a.id
not sure about the relations, but you can replace JOIN with LEFT JOIN if that's your case.
UPDATE
This should be working:
SELECT a.name as "name", sum(d.amount) as "amount"
FROM a
JOIN (SELECT id_a, amount FROM b UNION ALL SELECT id_a, amount FROM c) as d
on d.id_a = a.id
group by a.name
This yields the following results:
name1 | 800
name2 | 400
I have three table a,b,c having id common between them.
Table a:-
id name value
1 a 4
2 v 6
Table b:-
id abc
2 54
3 56
Table c:-
id bcd
1 54
3 34
Now what i want is what ever is id in where condition, data comes from all tables.
Please advice me how to do that.
Expected Result-
if query is
select * from a left join b on a.id=b.id left join c on a.id=c.id where b.id=3
id name value bcd abc
3 NULL NULL 34 56
if query is
select * from a left join b on a.id=b.id left join c on a.id=c.id where a.id=1
id name value bcd abc
3 a 4 54 NULL
What about this approach to the problem? :)
SELECT
z.id,
a.name,
a.value,
c.bcd,
b.abc
FROM
(
SELECT
DISTINCT y.id id
FROM
(
SELECT id FROM a
UNION ALL
SELECT id FROM b
UNION ALL
SELECT id FROM c
) y
) z
LEFT JOIN a ON z.id = a.id
LEFT JOIN b ON z.id = b.id
LEFT JOIN c ON z.id = c.id
where z.id = 3
sql fiddle
This way you just need to give the query the number not caring about which tables it exists in.
It's depends on what you are setting in WHERE condition. If you are setting WHERE b.ID = 3 then you need to join other tables with B like this:
SELECT A.ID AS A_ID,A.Name, A.value
,B.Id as B_ID,B.abc
,C.id AS C_ID, c.bcd
FROM b
LEFT JOIN a ON a.id = b.id
LEFT JOIN c ON a.id = c.id
WHERE b.id=3;
This is happens because b.ID = 3 is not in Table A and Table C is joined with Table A.
If you set Table A.ID = 1 then you have to join other tables with A using LEFT JOIN like this:
SELECT A.ID AS A_ID,A.Name, A.value
,B.Id as B_ID,B.abc
,C.id AS C_ID, c.bcd
FROM A
LEFT JOIN B ON a.id = b.id
LEFT JOIN c ON a.id = c.id
WHERE A.id=1;
See this SQLFiddle
This is technically impossible, when you are using ID in where how can you get data in case there Id not present in any of the perticular table, you are changing the logic of where ;).
But what you can do is
SELECT * FROM
(SELECT AID AS ID,NAME,VALUE FROM A
UNION
SELECT BID as ID,NAME,NULL AS VALUE FROM B
UNION
SELECT CID as ID,NAME ,NULL AS VALUE FROM C)
WHERE ID =''
Hope this helps
else please clarify. what you want.
Regards
Ashutosh Arya
I will try to guess, even though I barely find an explanation to the expected result:
SELECT
b.id,
a.name,
a.value,
c.bcd,
b.abc
FROM
b
INNER JOIN c ON b.id = c.id
LEFT JOIN a ON b.id = a.id
sql fiddle