MYSQL LEFT JOIN BRINGS WRONG RESULTS - mysql

I am trying to figure out why the join brings back the results it does.
Here is a simple test im working on.
I have two tables : Table1 and Table2.
table1
-------------------
id name amount
---------------------
1 | Fred | 2
3 | Fred | 3
5 | Fred | 4
2 | Hellen | 3
4 | Hellen | 3
6 | Hellen | 3
table2
-------------------
id name amount
---------------------
1 | Fred |4
2 | Hellen |3
3 | Paul |3
4 | Fridah |5
When i use the following statement
SELECT p.name,sum(p.amount) as amount FROM `table1` as p
left join table2 as c on p.name = c.name GROUP BY c.name , p.name
I get this result
---------------
name amount
---------------
Fridah | 5
Paul | 3
Fred | 12
Hellen | 9
But this is really wierd. I want the sum of amount from just table1, b ut the join gives me a sum of both tables. Why is this?

This is your query:
SELECT p.name, sum(p.amount) as amount
FROM `table1` as p left join
table2 as c
on p.name = c.name
GROUP BY c.name , p.name;
Your results suggest that the query you are running is:
SELECT p.name, sum(c.amount) as amount
-------------------^
FROM `table1` as p left join
table2 as c
on p.name = c.name
GROUP BY c.name , p.name;
If you run the correct query, you will get the results you expect.
EDIT:
The correct query would look like:
SELECT c.name, sum(p.amount) as amount
FROM table2 as c left join
table1 as p
on p.name = c.name
GROUP BY c.name;

Change the group by clause and include only p.name like GROUP BY p.name as below. See a demo fiddle here http://sqlfiddle.com/#!2/6c0e3/1
SELECT p.name,sum(p.amount) as amount
FROM `table1` as p
left join table2 as c on p.name = c.name
GROUP BY p.name
Results in
NAME AMOUNT
Fred 9
Hellen 9
EDIT:
You can calculate the sum individually and then join the derived tables in order to get the correct sum amount from both tables as below. See update fiddle Here
select X.name,X.amount,Y.amount2
from
(
select name,sum(amount) as amount
from table1
group by name
) X
left join
(
select name,sum(amount) as amount2
from table2
group by name
) Y on X.name = Y.name
Results In:
NAME AMOUNT AMOUNT2
Fred 9 4
Hellen 9 3

I have found an answer.
By adding distinct to the columns being summed, i was able to get the correct results.
have a look http://sqlfiddle.com/#!2/6c0e3/12/0
Thank you all for your help.

Related

The SUM of column in Join table SQL PHP not working [duplicate]

This question already has answers here:
MYSQL select join multiple table and SUM
(2 answers)
Closed 1 year ago.
I am trying to calculate and get the SUM of column count from table table_two. I am trying to fetch and get a sum of the column by the Left Join function. but it is not working correctly and the SUM of a column I am getting times of row to exist in table_two.
I am not perfect well in the union table with left JOIN could you please help me with how to use the union function in my code.
I show the multiple threads on this StackOverflow but believe me it was tough to understand and very big. that's why I am making here a small table for help and easily understandable.
Please help me don't mark it as duplicate and closed sir. I am trying for the past 1weeks but no code working.
I am trying the code is -
SELECT *, SUM(table_two.count) AS totalQTY, SUM(table_one.qty) AS totalReqQty
FROM table_one
LEFT JOIN table_two
ON table_one product_key = product_code
LEFT JOIN product_table
ON table_two.product_code = product_table.product_ids
table_one
| ID | product_key | insert_date | qty
|------|------------------|--------------|------
| 1 | 123456789 | 2021-02-01 | 150
------------------------------------------------
table_two
| ID | product_code | add_date | count
|------|-------------------|--------------|-------
| 1 | 123456789 | 2021-02-02 | 10
| 2 | 123456789 | 2021-02-03 | 20
| 3 | 123456789 | 2021-02-04 | 5
--------------------------------------------------
product_table
| ID | product_ids | product_name
|------|-------------------|----------------------
| 1 | 123456789 | XYZ
--------------------------------------------------
Expecting Output:
| ID | product_key | product_name | qty | count |
|------|-------------------|---------------------------------
| 1 | 123456789 | XYZ | 150 | 35 |
-------------------------------------------------------------
The query you showed us does not work.
If you want to summarize / roll up / your data by using aggregate functions like SUM() your best bet is to start by running the query without them. For example
SELECT *
FROM table_one
LEFT JOIN table_two
ON table_one.product_key = table_two.product_code
LEFT JOIN product_table
ON table_two.product_code = product_table.product_ids
You get this result. Notice that it has three rows, and the qty 150 shows up in all three.
ID
product_key
insert_date
qty
ID
product_code
add_date
count
ID
product_ids
product_name
1
123456789
2021-02-01
150
1
123456789
2021-02-02
10
1
123456789
XYZ
1
123456789
2021-02-01
150
2
123456789
2021-02-03
20
1
123456789
XYZ
1
123456789
2021-02-01
150
3
123456789
2021-02-04
5
1
123456789
XYZ
Then, keep in mind that when you sum up multiple rows, the detail in those rows (for example, table_1.ID) isn't meaningful any more. Which ID do you want when three rows are added up?
So you can do something like this
SELECT table_one.product_key,
SUM(table_two.count) totalQty,
SUM(table_one.qty) totalReqQty
FROM table_one
LEFT JOIN table_two
ON table_one.product_key = table_two.product_code
LEFT JOIN product_table
ON table_two.product_code = product_table.product_ids
GROUP BY table_one.product_key
That gives this result, which is incorrect -- it triple-sums table_one.qty. Your JOIN of table_one and table_two caused a combinatorial explosion.
product_key
totalQty
totalReqQty
123456789
35
450 WRONG!
So, what you need in is to understand that your top level FROM table_one ... JOIN table_two ... JOIN product_table... pattern needs to join together a single row in table_one, table_two, and product_table for each product. In this setup you're fine for product_table. It has one row for each product.
But the other tables can have multiple rows per product. So you need to SUM them in subqueries, and join the subqueries, like this.
SELECT product_table.product_ids,
table_two_summary.totalQty,
table_one_summary.totalReqQty
FROM product_table
LEFT JOIN (
SELECT product_code, SUM(count) totalQty
FROM table_two
GROUP BY product_code
) table_two_summary
ON product_table.product_ids = table_two_summary.product_code
LEFT JOIN (
SELECT product_key, SUM(qty) totalReqQty
FROM table_one
GROUP BY product_key
) table_one_summary
ON product_table.product_ids = table_one_summary.product_key
Edit if you need to filter on the summed-up columns you can do it like this.
SELECT product_table.product_ids,
table_two_summary.totalQty,
table_one_summary.totalReqQty
FROM product_table
LEFT JOIN (
SELECT product_code, SUM(count) totalQty
FROM table_two
GROUP BY product_code
) table_two_summary
ON product_table.product_ids = table_two_summary.product_code
LEFT JOIN (
SELECT product_key, SUM(qty) totalReqQty
FROM table_one
GROUP BY product_key
) table_one_summary
ON product_table.product_ids = table_one_summary.product_key
WHERE table_one_summary.totalReqQty > table_two_summary.totalQty
See how the subqueries summarize the two different tables separately. If you join them and summarize them you'll count some rows multiple times.
You haven't tagged the database you are using, however one way to obtain the aggregations from each would be using apply.
I would also suggest you amend the inconsistencies in the naming convention of your ProductId, you are referring to it as product_code and product_key and product_ids. Deciding what to call it and being consistent will make it much easier for others to understand.
select p.product_ids as product_key, p.product_name, coalesce(q.Qty,0) totalQty, coalesce(c.[count],0) [Count]
from product_table p
outer apply (
select sum(qty) Qty
from table_one t1
where t1.product_key=p.product_ids
group by t1.product_key
)q
outer apply (
select Sum(count) [count]
from table_two t2
where t2.product_code=p.product_ids
group by t2.product_code
)c

Set Alias in SELECT with Inner Join

I have a 2 tables:
People table:
id | name | date
1 | Mika | 2013
2 | Rose | 2015
Work table:
id | user_id | work_name | registers
1 | 1 | rugby | 10
2 | 1 | golf | 3
I use this query to join tables:
SELECT * FROM work INNER JOIN people ON work.user_id = people.id WHERE work_name= :work_name
This work it, but I get duplicate column ID and in php when I try to print the camp id, this show the last column id..
I try with this but dont work it:
SELECT *, id AS 'work_id'
FROM work
INNER JOIN people ON work.user_id = people.id
WHERE work_name= :work_name
That is because you are using * in the SELECT that mean will bring all the fields from boths tables instead you can use
SELECT work.id as work_id,
work.name as work_name,
work.date as work_date,
people.id as people_id,
people.name as people_name,
people.date as people_date
Try to manually list all of columns you need to display, for instance
SELECT w.user_id, w.work_name, w.registers, p.name, p.date FROM work as w INNER JOIN people as p ON work.user_id = people.id WHERE work_name= :work_name

Sum columns from two tables in sql

I have two tables, one is the cost table and the other is the payment table, the cost table contains the cost of product with the product name.
Cost Table
id | cost | name
1 | 100 | A
2 | 200 | B
3 | 200 | A
Payment Table
pid | amount | costID
1 | 10 | 1
2 | 20 | 1
3 | 30 | 2
4 | 50 | 1
Now I have to sum the total of cost by the same name values, and as well sum the total amount of payments by the costID, like the query below
totalTable
name | sum(cost) | sum(amount) |
A | 300 | 80 |
B | 200 | 30 |
However I have been working my way around this using the query below but I think I am doing it very wrong.
SELECT
b.name,
b.sum(cost),
a.sum(amount)
FROM
`Payment Table` a
LEFT JOIN
`Cost Table` b
ON
b.id=a.costID
GROUP by b.name,a.costID
I would be grateful if somebody would help me with my queries or better still an idea as to how to go about it. Thank you
This should work:
select t2.name, sum(t2.cost), coalesce(sum(t1.amount), 0) as amount
from (
select id, name, sum(cost) as cost
from `Cost`
group by id, name
) t2
left join (
select costID, sum(amount) as amount
from `Payment`
group by CostID
) t1 on t2.id = t1.costID
group by t2.name
SQLFiddle
You need do the calculation in separated query and then join them together.
First one is straight forward.
Second one you need to get the name asociated to that payment based in the cost_id
SQL Fiddle Demo
SELECT C.`name`, C.`sum_cost`, COALESCE(P.`sum_amount`,0 ) as `sum_amount`
FROM (
SELECT `name`, SUM(`cost`) as `sum_cost`
FROM `Cost`
GROUP BY `name`
) C
LEFT JOIN (
SELECT `Cost`.`name`, SUM(`Payment`.`amount`) as `sum_amount`
FROM `Payment`
JOIN `Cost`
ON `Payment`.`costID` = `Cost`.`id`
GROUP BY `Cost`.`name`
) P
ON C.`name` = P.`name`
OUTPUT
| name | sum_cost | sum_amount |
|------|----------|------------|
| A | 300 | 80 |
| B | 200 | 30 |
A couple of issues. For one thing, the column references should be qualified, not the aggregate functions.
This is invalid:
table_alias.SUM(column_name)
Should be:
SUM(table_alias.column_name)
This query should return the first two columns you are looking for:
SELECT c.name AS `name`
, SUM(c.cost) AS `sum(cost)`
FROM `Cost Table` c
GROUP BY c.name
ORDER BY c.name
When you introduce a join to another table, like Product Table, where costid is not UNIQUE, you have the potential to produce a (partial) Cartesian product.
To see what that looks like, to see what's happening, remove the GROUP BY and the aggregate SUM() functions, and take a look at the detail rows returned by a query with the join operation.
SELECT c.id AS `c.id`
, c.cost AS `c.cost`
, c.name AS `c.name`
, p.pid AS `p.pid`
, p.amount AS `p.amount`
, p.costid AS `p.costid`
FROM `Cost Table` c
LEFT
JOIN `Payment Table` p
ON p.costid = c.id
ORDER BY c.id, p.pid
That's going to return:
c.id | c.cost | c.name | p.pid | p.amount | p.costid
1 | 100 | A | 1 | 10 | 1
1 | 100 | A | 2 | 20 | 1
1 | 100 | A | 4 | 50 | 1
2 | 200 | B | 3 | 30 | 2
3 | 200 | A | NULL | NULL | NULL
Notice that we are getting three copies of the id=1 row from Cost Table.
So, if we modified that query, adding a GROUP BY c.name, and wrapping c.cost in a SUM() aggregate, we're going to get an inflated value for total cost.
To avoid that, we can aggregate the amount from the Payment Table, so we get only one row for each costid. Then when we do the join operation, we won't be producing duplicate copies of rows from Cost.
Here's a query to aggregate the total amount from the Payment Table, so we get a single row for each costid.
SELECT p.costid
, SUM(p.amount) AS tot_amount
FROM `Payment Table` p
GROUP BY p.costid
ORDER BY p.costid
That would return:
costid | tot_amount
1 | 80
2 | 30
We can use the results from that query as if it were a table, by making that query an "inline view". In this example, we assign an alias of v to the query results. (In the MySQL venacular, an "inline view" is called a "derived table".)
SELECT c.name AS `name`
, SUM(c.cost) AS `sum_cost`
, IFNULL(SUM(v.tot_amount),0) AS `sum_amount`
FROM `Cost Table` c
LEFT
JOIN ( -- inline view to return total amount by costid
SELECT p.costid
, SUM(p.amount) AS tot_amount
FROM `Payment Table` p
GROUP BY p.costid
ORDER BY p.costid
) v
ON v.costid = c.id
GROUP BY c.name
ORDER BY c.name

Sum columns from multiple tables in MySQL

I am trying to sum some columns from multiple tables in just one SQL query, but I seem to be getting the wrong results. I think there is a problem with the code that I have provided below. Please any help on this is appreciated.
item Names
| id | name |
| 1 | AB |
| 2 | CA |
table1
| id | interest | year |
| 1 | 20.00 | 2014 |
| 2 | 30.00 | 2013 |
| 1 | 10.00 | 2013 |
table2
| id | deposit | year |
| 1 | 10.00 | 2014 |
| 2 | 10.00 | 2014 |
This is the query that I tried:
SELECT
a.name,
b.year,
sum(b.interest) as 'total'
FROM
`table1` b
INNER JOIN
`item names` a
ON
b.id=a.id
GROUP BY
b.id
UNION ALL
SELECT
c.name,
d.year,
sum(d.deposit) as 'total'
FROM
`table2` d
INNER JOIN
`item names` c
ON
d.id=c.id
GROUP BY
d.id
EXPECTED RESULTS
UPDATE
I am trying to find the total sum of interest and deposit for a particular year and for a particular item
|name | year | total |
| AB | 2014 | 30.00 |
| AB | 2013 | 10.00 |
| CA | 2013 | 30.00 |
| CA | 2014 | 10.00 |
Perhaps... assuming table1 and table2 have same structure.
First I generate a set with the union values from one and two then we use a simple aggregate and a group by to sum the values by name and year.
SELECT I.Name, B.year, Sum(B.Total)
FROM item I
INNER JOIN
(SELECT * FROM table1 UNION select * FROM table2) B
on B.ID = I.ID
GROUP BY I.Name, B.Year
In the query you have posted, you need to group by year also to get the results. Then, you can use UNION to get all of the rows from the first set, along with all of the rows from the second set:
SELECT a.name, b.year, SUM(b.interest) AS total
FROM names a
JOIN table1 b ON b.id = a.id
GROUP BY a.name, b.year
UNION
SELECT a.name, c.year, SUM(c.deposit) AS total
FROM names a
JOIN table2 c ON c.id = a.id
GROUP BY a.name, c.year;
However, this doesn't give you your final results, as names that appear in each table ('AB' for example) will appear twice. One row for the year in deposits, one row for the year in interests. To combine those, just use the above as a subquery, sum the totals and again group by name and date:
SELECT name, year, SUM(total) AS total
FROM(
SELECT a.name, b.year, SUM(b.interest) AS total
FROM names a
JOIN table1 b ON b.id = a.id
GROUP BY a.name, b.year
UNION
SELECT a.name, c.year, SUM(c.deposit) AS total
FROM names a
JOIN table2 c ON c.id = a.id
GROUP BY a.name, c.year) temp
GROUP BY name, year;
Here is an SQL Fiddle example.

How to merge the rows of a second table into 1 field

I've been trying to produce a query that will search table1, and then CONCAT the all the values of table2.column1 where table1.id = table2.owner
People
name | id
-------------
tim | 1
jill | 2
john | 3
Dogs
name | owner
--------------
a | 1
b | 1
c | 2
d | 2
Using the following table i need a query that would output
name | dogs
-----------
tim | a, b
jill | c, d
john | NULL (or a blank text or just so long as the name john still shows)
I have spent a few hours and really cant do it. Some form of mash between OUTER JOIN, and group_concat(), i think. But i didnt really get close to my answer.
Thank you for all help!
You will want to use GROUP_CONCAT and a GROUP BY
SELECT p.name, GROUP_CONCAT(d.name)
FROM people p
LEFT JOIN dogs d
ON p.id = d.owner
GROUP BY p.name
see SQL Fiddle with Demo
I guess you looking for GROUP_CONCAT in MySQL.
SELECT a.name, GROUP_CONCAT(b.name) dogsName
FROM People a
LEFT JOIN Dogs b
ON a.id = b.owner
GROUP BY a.name
SQLFiddle Demo