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
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 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.
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
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.