This question already has answers here:
Sum total of table with two related tables
(2 answers)
Closed 9 years ago.
I have 4 tables, with the relevant columns summarized here:
customers:
id
name
credits:
id
customer_id # ie customers.id
amount
sales:
id
customer_id # ie customers.id
sales_items:
id
sale_id # ie sales.id
price
discount
The idea is that customers lists all of our customers, credits lists each time they have paid us, sales lists each time they have bought things from us (but not what things they bought) and sales_items lists all of the items they bought at each of those sales. So you can see that credits and sales both relate back to customers, but sales_items only relates back to sales.
As an example dataset, consider:
customers:
id | name
5 | Carter
credits:
id | customer_id | amount
1 | 5 | 100
sales:
id | customer_id
3 | 5
sales_items:
id | sale_id | price | discount
7 | 3 | 5 | 0
8 | 3 | 0 | 0
9 | 3 | 10 | 0
I have tried this in MySQL:
SELECT c.*,
SUM( cr.amount ) AS paid,
SUM( i.price + i.discount ) AS bought
FROM customers AS c
LEFT JOIN sales AS s ON s.customer_id = c.id
LEFT JOIN sales_items AS i ON i.sale_id = s.id
LEFT JOIN credits AS cr ON cr.customer_id = c.id
WHERE c.id = 5
But it returns:
id | name | paid | bought
5 | Carter | 300 | 15
If I omit the SUM() functions, it returns:
id | name | paid | bought
5 | Carter | 100 | 5
5 | Carter | 100 | 0
5 | Carter | 100 | 15
So it looks like it's returning one row for every record matched in sales_items, but it's filling in the amount column with same value from credits each time. I see that this is happening, but I'm not understanding why it's happening.
So, two questions:
1. What is happening that it's smearing that one value through all of the rows?
2. What SQL can I throw at MySQL so that I can get this back:
id | name | paid | bought
5 | Carter | 100 | 15
I know that I could break it all up in subqueries, but is there a away to do it just with joins? I was hoping to learn a thing or two about joins as I tackled this problem. Thank you.
Edit: I created an SQL Fiddle for this: http://sqlfiddle.com/#!2/0051b/1/0
select distinct (c.id, c.name), sum(i.price+i.discount) AS bought, cr.amount AS paid
from customer c, credits cr, sales s, sales_items i
where s.customer_id = c.id
and i.sale_id = s.id
and cr.customer_id = c.id and c.id = 5
group by c.id, c.name;
I'm not very sure, but try this. Use group by; that is surely the solution.
Please try this
SELECT c.*,( SELECT SUM( cr.amount ) FROM customer c INNER JOIN credits cr ON
cr.customer_id = c.id WHERE c.id = 5 GROUP BY cr.id ) AS paid
,SUM( i.price + i.discount ) AS bought
FROM customers AS c INNER JOIN sales s ON s.customer_id = c.id
INNER JOIN sales_items i ON i.sale_id = s.id
INNER JOIN credits cr ON cr.customer_id = c.id
WHERE c.id = 5 GROUP BY s.id,cr.id
Related
I've two tables.
User(id,name)
Finance(id,item_id,amount,user_id)
My use case is
users are the employees (sales guys) of the organization.
When they sell an item finance table get updated with a new record of that sold item's serial id.
I want to get the user names along with the total value of the sales they made.
User
id | name
1 | Dinesh
2 | Pathum
3 | Naveed
Finance
id | item_id | amount | user_id
1 | 1 | 2000 | 1
2 | 2 | 2000 | 1
3 | 3 | 1000 | 3
4 | 4 | 500 | 3
Expected output
Dinesh 4000
Pathum 0
Naveed 1500
How do I achieve this using MySQL?
The query is like the following:
SELECT u.name as 'Agent Name',
if(sum(f.amount) IS NULL, 0,sum(f.amount)) as Total,
f.createdAt
FROM users u LEFT JOIN finance f
ON u.id = f.user_id
GROUP BY u.id, u.name, f.createdAt
ORDER BY f.createdAt DESC
Here is a working SQL Fiddle.
Join em, group em, sum em.
SELECT usr.name AS UserName, COALESCE(SUM(fin.amount),0) AS TotalAmount
FROM `User` usr
LEFT JOIN `Finance` fin ON fin.user_id = usr.id
GROUP BY usr.id, usr.name
ORDER BY usr.id;
Test on db<>fiddle here
Another way:
SELECT Name,SUM(IFNULL(amount,0)) AS "Total" FROM (SELECT Name,amount FROM user LEFT JOIN finance ON user.id=finance.user_id) a GROUP BY Name;
This question already has an answer here:
MySql Count cannot show 0 values
(1 answer)
Closed 5 years ago.
The thing, that I'm trying to do is:
Fetch room availability count based on supplied checkin and checkout dates.
Here are the tables:
categories
id | name
1 | Luxe
2 | Deluxe
reservations
id | category_id | checkin | checkout
1 | 1 | 2018-01-06 | 2018-01-10
1 | 2 | 2018-01-11 | 2018-01-13
3 | 2 | 2018-01-13 | 2018-01-17
Expected output
Since category_id = 2 is available from 2018-01-06 up to 2018-01-10 (see the very first row in reservations table), I'm trying to include its availability count, when fetching total count.
So when running this query
SELECT
categories.name AS category,
COUNT(reservations.id) AS free_count
FROM reservations
INNER JOIN categories ON categories.id = reservations.category_id
WHERE checkin BETWEEN '2018-01-06' AND '2018-01-10'
GROUP BY categories.name, reservations.id
The output is:
category | free_count
Luxe | 1
However I'm willing the output to be:
category | free_count
Luxe | 1
Deluxe | 0
i.e replace non-matching rows to zero. How this can be done? A solution without nested queries (due to their slow performance) is very encouraged.
Use LEFT JOIN instead of INNER JOIN
SELECT
c.name AS category,
COUNT(r.id) AS free_count
FROM categories c
LEFT JOIN reservations r
ON c.id = r.category_id
AND checkin BETWEEN '2018-01-06' AND '2018-01-10'
GROUP BY c.name
Its important to keep the checkin filter in ON condition. When you keep the right table filter in Where clause, the non matching records will have NULL values which will be filtered in result due the where condition(basically Left join will be converted to Inner join)
I've two tables invoices and products.
invoices: store,
products: id, invoice_id
I want to have a result set that shows how many invoices exists for each quantity of products.
I mean, if I have 2 invoices with 3 products each on store A, it will show Store: A, Products qty: 3, Number of invoices (with three products): 2
Another example:
| store | products_qty | count |
| A | 1 | 10 |
| A | 2 | 7 |
| A | 5 | 12 |
| B | 5 | 12 |
Meaning, store A has 10 invoices with 1 product. 7 with 2 products, and 12 with 5 products...
I've tried with something like:
SELECT store, count(p.id), count(i.id) FROM invoices i
LEFT JOIN products p ON (p.invoice_id = i.id)
GROUP BY price, count(i.id)
however my group cause is not valid, it shows Invalid use of group function.
How can I accomplish this?
I was able to do using subqueries, I wonder if is possible without it:
SELECT store, products_qty, count(*) FROM (
SELECT store, count(p.id) as products_qty, count(i.id) as invoices_count
FROM invoices i
LEFT JOIN products p ON (p.invoice_id = i.id)
GROUP BY price, i.id
) AS temp GROUP BY store, products_qty;
I have a MySQL DB with the following Tables:
Products:
Product_ID | Product_Name
1 | Blaster
2 | Faser
3 | BFG
Orders:
Order_ID | Product_ID | Order_Product_Qnt
1 | 1 | 10
2 | 2 | 5
3 | 3 | 7
4 | 2 | 10
Sells:
Sell_ID | Product_ID | Sel_Product_Qnt
1 | 2 | 5
2 | 1 | 1
3 | 3 | 2
What I want to do is a query that lists all the products followed by their amount.
The result should be:
Product_Name | Quantity
BFG | 5
Blaster | 9
Faser | 10
Following Barnar's suggestion I got to this piece of code:
SELECT
Products.Product_Name,
COALESCE (SUM(Orders.Order_Product_Qnt), 0) - COALESCE (SUM(Sells.Sells_Product_Qnt), 0) AS Quantity
FROM
Products
LEFT JOIN
Orders ON Products.Product_ID = Orders.Product_ID
LEFT JOIN
Sells ON Products.Product_ID = Sells.Product_ID
GROUP BY
Products.Product_Name
The query works but it returns wrong values.
For example, I have a product that has 6 orders, and 1 sell, logic dictates that 6-1=5, but that query gives me 4 as a result.
Or another one with 18 Orders and 6 Sells, returns 60 (should be 12).
Any advise is appreciated.
Maybe something like this?
SELECT
product_name,
orders_cnt - sales_cnt AS Quantity
FROM (
SELECT product_name,
SUM(orders) AS orders_cnt,
SUM(sales) AS sales_cnt
FROM (
SELECT products.product_name,
ifnull(orders.order_product_qnt, 0) orders,
ifnull(sells.sells_product_qnt,0) sales
FROM products
LEFT JOIN orders ON products.product_id = orders.product_id
LEFT JOIN sells ON products.product_id = sells.product_id
) t1
GROUP BY product_name ) t2
Finally got it working, forgot to post my solution here:
SELECT
Products.Product_ID,
Products.Product_Name,
IFNULL(b.SB - c.SC, 0) AS Quantity,
FROM Produtos_Table
LEFT JOIN (
SELECT
Product_ID,
SUM(Quantity) AS SB
FROM
Orders
GROUP BY Product_ID
) b
ON Products.Product_ID = b.Product_ID
LEFT JOIN (
SELECT
Product_ID,
SUM(Sell_Product_Qnt) AS SC
FROM
Sells
GROUP BY
Product_ID
) c
ON Products.Product_ID = c.Product_ID
GROUP BY
Products.Product_Name
I have the following tables (they all got more columns but I'm just showing the ones of interest):
Product Order details Orders
---------------------------- ---------------------------- --------------
| id_product | id_supplier | | id_order | id_product | | id_order |
| 12 | 2 | | 1 | 56 | | 1 |
| 32 | 4 | | 2 | 32 | | 2 |
| 56 | 2 | | 2 | 56 | | 3 |
| 10 | 1 | | 4 | 56 | | 4 |
---------------------------- | 3 | 12 | --------------
----------------------------
What I want to do is select all orders which have products from ONLY one or more suppliers. So lets say I want all orders that only have products from the supplier with id 2 (id_supplier = 2) I should get the orders with id 1, 3 and 4.
If I want all orders that ONLY have products from the supplier with id 4 (id_supplier = 4) I should get an empty result.
If I want all orders that ONLY have products from the suppliers with id 2 AND 4 I should get the order with id 2.
I've read the following question: mySQL exclusive records but I can't get a grip of that query to work when I have two tables like I have. I just need another pair of eyes to help me out here! :)
Do you have any idea on how I'll do this?
EDIT: To clearify, I want to fetch all orders that ONLY contains products from one or more specified suppliers. Orders with products from other suppliers than is specified, should not be included.
per the questions I've listed, I think THIS is what you want, and can be done with a LEFT join.
select
od.id_order,
sum( if( p.id_supplier in ( 2, 4 ), 1, 0 )) as HasSupplierLookingFor,
sum( if( p.id_supplier in ( 2, 4 ), 0, 1 )) as HasOtherSuppliers
from
order_Details od
join product p
on od.id_product = p.id_product
group by
od.id_order
having
HasSupplierLookingFor > 0
AND HasOtherSuppliers = 0
Sometimes, just answering a question that can be somewhat ambiguous as presented leads to misrepresented answers. This query will by a per order basis, join to the products to find the suppliers and group by the order id.
For each product ordered, the first SUM() asks if its one of the suppliers you ARE looking for, if so, sum a value of 1, otherwise 0... The next SUM() asks the same thing... but if it IS the supplier, use zero, thus all OTHER suppliers gets the 1.
So, now, the HAVING clause is looking for any order that at a minimum of 1 of your suppliers qualified AND it had no other suppliers represented.
So you could have an order with 30 items, and 20 from supplier 2, and 10 from supplier 4. The HasSupplierLookingFor would = 30, and HasOtherSuppliers = 0, the order would be included.
Another order could have 5 items. One from supplier 2, and 4 others from supplier 9. This would have HasSupplierLookingFor = 1, and HasOtherSuppliers = 4, thus exclude this as a qualified order.
You should inner join all those tables, like this:
SELECT o.* from Orders o
INNER JOIN Details d ON o.id_order = d.id_order
INNER JOIN Products p ON d.id_product = p.id_product
WHERE p.id_supplier = 4
That will give you the orders which include products from that supplier.
SELECT o.id_order
FROM Orders o
INNER JOIN `Order details` od
ON o.id_order = od.id_order
INNER JOIN Product p
ON p.id_product = od.id_product
WHERE p.id_supplier IN (2,4)
the (2,4) are the suppliers you want to fetch. you can also ask for only 1 by saying (2)