I have multiple tables and I need to aggregate the data from all of them, but it seems that I always get the wrong results for the sums. What am I doing wrong?
customers
ID Name
1 c1
2 c2
3 c3
budget
ID Cust_ID Value
1 1 100
2 1 300
3 2 600
4 3 450
forecast
ID Cust_ID Value
1 1 200
2 1 500
3 2 100
4 2 700
5 3 550
orders
ID Cust_ID Net_Sales
1 1 100
2 1 200
3 1 300
4 2 400
5 3 500
Here is the expected result:
ID Name sum(budget.Value) sum(forecast.Value) sum(orders.Net_Sales) count(orders.ID)
1 c1 400 700 600 3
2 c2 600 800 400 1
3 c3 450 550 500 1
And here's what I've tried so far:
SELECT customers.ID, customers.Name, sum(budget.Value), sum(forecast.Value), sum(orders.Net_Sales), count(orders.ID)
FROM customers
INNER JOIN budget ON budget.Cust_ID = customers.ID
INNER JOIN forecast ON forecast.Cust_ID = customers.ID
INNER JOIN orders ON orders.Cust_ID = customers.ID
GROUP BY customers.ID
ORDER BY customers.ID ASC
You are joining along multiple dimensions, which multiplies the results.
A simple solution is correlated subqueries:
SELECT c.ID, c.Name,
(SELECT SUM(b.Value)
FROM budget b
WHERE b.Cust_ID = c.ID
) as budget,
(SELECT SUM(f.Value)
FROM forecast f
WHERE f.Cust_ID = c.ID
) as forecast,
(SELECT SUM(o.Net_Sales)
FROM orders o
WHERE o.Cust_ID = c.ID
) as net_sales
FROM customers c
ORDER BY c.ID ASC;
With the right indexes in the second tables (budget(cust_id, value), and so on), this may actually be faster than a JOIN approach.
Related
I've the two tables orders
id article amount
1 1 1
2 2 50
and prices
id article min_amount price
1 1 1 42.99
2 2 1 5.06
3 2 5 4.55
4 2 10 4.3
5 2 25 4.05
6 2 100 2.66
The prices tables contains IDs of articles and a minimum amount you would have to buy to get a bulk discount (which would change the price for the order). I would like to join prices into orders, so that the result looks like:
id article amount price
1 1 1 42.99
2 2 50 4.05
The order id 2 is above the minimum (25) to get the article for 4.05€, but still below 100 at which you would get a bigger discount, so the query would to have pick the next-lower value.
I've tried this query so far
SELECT
orders.id AS id,
orders.article,
orders.amount,
prices.price,
(orders.amount - prices.min_amount) AS discount_diff
FROM orders
LEFT JOIN prices ON (prices.article = orders.article) AND (prices.min_amount <= orders.amount)
which gives this result
id article amount price discount_diff
1 1 1 42.99 0
2 2 50 5.06 49
2 2 50 4.55 45
2 2 50 4.3 40
2 2 50 4.05 25
You can find this example on "js"fiddle: http://sqlfiddle.com/#!9/1b2bf/8
The query you need is this:
SELECT orders.id AS id,
orders.article,
orders.amount,
prices.price
FROM orders
INNER JOIN prices ON ( prices.article = orders.article
and prices.min_amount <= orders.amount)
INNER JOIN ( SELECT orders.article,
orders.amount,
min(prices.price) minprince
FROM orders
INNER JOIN prices ON (prices.article = orders.article
AND prices.min_amount <= orders.amount)
GROUP BY orders.article,
orders.amount) b
ON ( prices.article = b.article
AND orders.amount = b.amount
AND prices.price = b.minprince)
See it here: http://sqlfiddle.com/#!9/1b2bf/27
I would like to change the order by clause in function of a field, but I don't know whether it's possible or not.
Here is an example:
**TABLE DISCOUNTS**
category offer
A 0
B 0
C 1
D 1
F 0
product_id category price
1 A 100
2 B 300
3 C 250
4 C 150
5 D 200
6 B 200
7 F 250
I'm willing to select all the products but already ordered, firstly if they are an offer or not (I want to show offers first), and after that I want to group them by category and sorted by price.
The problem is with the offers, here is not important to group by category because won't be too many offers and makes more sense to directly show them sorted by price.
So here is the ouput I'm getting:
product_id category price offer
4 C 150 1
3 C 250 1
5 D 200 1
1 A 100 0
6 B 200 0
7 F 250 0
2 B 300 0
While I would like to get a different order (sorting offers only by price):
product_id category price offer
4 C 150 1
5 D 200 1
3 C 250 1
1 A 100 0
6 B 200 0
2 B 300 0
7 F 250 0
The query I'm using is:
select * from Products p
left join Discounts d on p.category = d.category
order by offer desc, p.category, price
and here is the fiddle
What would be the best option here?
Thanks.
I think you just need to remove category from the order by:
select *
from Products p left join
Discounts d
on p.category = d.category
order by offer desc,
(case when offer = 0 then category end),
price ;
As I understand it you want offers ordered by price only and non offers order by category then price. In that case you can use an IF to conditionally order:
select * from Products p
left join Discounts d on p.category = d.category
order by offer desc,IF(offer,price,p.category), p.category, price
I have 3 tables. A table for product prices, invoiced products, and ordered products. I am trying to create a view that joins these. I want to output the product prices with a total of invoiced products and a total of ordered products.
products_price
id season_id product_id product_price
1 1 1 3.99
2 1 2 6.99
3 1 3 5.99
4 1 4 5.99
....
invoices_products
id season_id invoice_id product_id piece_qty
1 1 1 1 1600
2 1 2 2 3200
3 1 3 2 200
4 1 4 1 120
....
orders_products
id season_id order_id product_id piece_qty
1 1 1 1 160
2 1 2 1 40
3 1 2 2 20
4 1 3 2 10
....
Here are a few queries from the View statements I've tried so far.
This query gives me everything I want. The View's output is perfect but the SUM() for the first 2 rows is off. total_invoice_product is double for row 1 and 2. total_order_productis 4x for row 1 and 3x for row 2.
Statement 1:
SELECT
`t1`.`id` AS `id`,
`t1`.`season_id` AS `season_id`,
`t1`.`product_id` AS `product_id`,
`t1`.`product_piece_price` AS `product_piece_price`,
SUM(`t2`.`piece_qty`) AS `total_invoice_product`,
SUM(`t3`.`piece_qty`) AS `total_order_product`
FROM
((`products_price` `t1`
LEFT JOIN `invoices_products` `t2` ON (((`t2`.`product_id` = `t1`.`product_id`)
AND (`t2`.`season_id` = `t1`.`season_id`))))
LEFT JOIN `orders_products` `t3` ON (((`t3`.`product_id` = `t1`.`product_id`)
AND (`t3`.`season_id` = `t1`.`season_id`))))
GROUP BY `t1`.`season_id` , `t1`.`product_id`
This query gives me the output that I expect. Its not the full output I want but its correct for the statement. The SUM() totals are off on this one as well.
Statement 2:
SELECT
`t1`.`id` AS `id`,
`t1`.`season_id` AS `season_id`,
`t1`.`product_id` AS `product_id`,
`t1`.`product_price` AS `product_price`,
SUM(`t2`.`piece_qty`) AS `total_invoice_product`,
SUM(`t3`.`piece_qty`) AS `total_order_product`
FROM
((`products_price` `t1`
LEFT JOIN `invoices_products` `t2` ON ((`t2`.`product_id` = `t1`.`product_id`)))
LEFT JOIN `orders_products` `t3` ON ((`t3`.`product_id` = `t1`.`product_id`)))
WHERE
((`t2`.`season_id` = `t1`.`season_id`)
AND (`t2`.`product_id` = `t1`.`product_id`))
GROUP BY `t1`.`season_id` , `t1`.`product_id`
the output I want
id season_id product_id product_price total_invoice total_order
1 1 1 3.99 1720 200
2 1 2 6.99 3400 30
3 1 3 5.99 576
4 1 4 5.99 800
output received for statement 1
id season_id product_id product_price total_invoice total_order
1 1 1 3.99 3440 800
2 1 2 6.99 6800 90
3 1 3 5.99 576
4 1 4 5.99 800
output received for statement 2
id season_id product_id product_price total_invoice total_order
1 1 1 3.99 3440 800
2 1 2 6.99 6800 90
I can build a query like below and it works perfect. I get the exact output I need but this code does not work as a view. I get this error: ERROR 1349: View's SELECT contains a subquery in the FROM clause SQL Statement
Perfect Query but will not work as a view
SELECT
products_price.id,
products_price.season_id,
products_price.product_id,
products_price.product_price,
invoices_grouped.total_invoice_product,
orders_grouped.total_order_product
FROM
products_price
LEFT JOIN
(SELECT
invoices_products.product_id,
invoices_products.season_id,
SUM(invoices_products.piece_qty) AS total_invoice_product
FROM
invoices_products
GROUP BY
invoices_products.product_id) AS invoices_grouped
ON
invoices_grouped.product_id = products_price.product_id
AND
invoices_grouped.season_id = products_price.season_id
LEFT JOIN
(SELECT
orders_products.product_id,
orders_products.season_id,
SUM(orders_products.piece_qty) AS total_order_product
FROM
orders_products
GROUP BY
orders_products.product_id) AS orders_grouped
ON
orders_grouped.product_id = products_price.product_id
AND
orders_grouped.season_id = products_price.season_id
What I need
I've tried several other statements. They either got worse results or the same. Can someone help me get Statement 1 working with a proper SUM?
Edit 1 for a question
The information that this view provides will be called upon a lot. The products_price and invcoices_products tables will not be changed that often. orders_products will be changed a lot. If 2 views are required, would it be more efficient to use the "Perfect" query above or use 2 views?
Edit 2 for another query
Here is another query from my view statement. This query is part of Statement 1 shown above. This query works perfect but it is not complete. I need the second SUM column. When you add the second LEFT JOIN it breaks the SUM totals.
SELECT
`t1`.`id` AS `id`,
`t1`.`season_id` AS `season_id`,
`t1`.`product_id` AS `product_id`,
`t1`.`product_piece_price` AS `product_piece_price`,
SUM(`t2`.`piece_qty`) AS `total_invoice_product`
FROM
(`products_price` `t1`
LEFT JOIN `invoices_products` `t2` ON (((`t2`.`product_id` = `t1`.`product_id`)
AND (`t2`.`season_id` = `t1`.`season_id`))))
GROUP BY `t1`.`season_id` , `t1`.`product_id`
output
id season_id product_id product_price total_invoice
1 1 1 3.99 1720
2 1 2 6.99 3400
3 1 3 5.99 576
4 1 4 5.99 800
Well, MySql has some limitations, so you will need to create 2 views for subqueries and use them:
create view viewInvoices
as
select season_id, product_id, sum(piece_qty) pq
from invoices_products group by season_id, product_id
create view viewOrders
as
select season_id, product_id, sum(piece_qty) pq
from orders_products group by season_id, product_id
select pp.id,
pp.season_id,
pp.product_id,
pp.product_price,
i.pq as total_invoice,
o.pq as total_order
from products_price pp
left join viewInvoices as i
on pp.season_id = i.season_id and pp.product_id = i.product_id
left join viewOrders as o
on pp.season_id = o.season_id and pp.product_id = o.product_id
Try this query
SELECT * from products_price as a left join (select product_id, sum(piece_qty)total_invoices from invoices_products group by product_id) as b on a.product_id=b.product_id left join (select product_id, sum(piece_qty) as total_order from orders_products group by product_id) as c on a.product_id=c.product_id
I have a table pur with values as
CUST_ID AMOUNT
1 100
3 50
1 200
1 500
3 20
and table cus with values as:
CUST_ID
1
2
3
How do I get to show this:
CUST_ID Total_AMOUNT
2 0
3 70
1 800
Simply put, how do I show 2 columns from cus table?
You can use LEFT JOIN and then get SUM of the AMOUNT by grouping rows with the same CUST_ID :
SELECT t2.CUST_ID
, COALESCE(SUM(t1.AMOUNT), 0) AS TOTAL
FROM cus t2 LEFT JOIN pur t1 ON t1.CUST_ID = t2.CUST_ID
GROUP BY t2.CUST_ID
ORDER BY TOTAL
SQLFiddle
I have this working query
SELECT t1.id as stockid, t1.description as stockdescription, t2.inkoop as price , COUNT(t2.inkoop) as cnt,
(t2.inkoop * COUNT(t2.inkoop)) as totalamount
FROM database1.table_products t1
LEFT JOIN database1.table_stock t2 ON t1.id = t2.stock_id
WHERE 1
GROUP BY t2.inkoop
ORDER BY t1.id ASC
1 database, 2 tables:
t1 is the products 'description' database with ids and description
t2 is the stock, which has a lot of products for what price (purchased) and referenced by stock_id
Output:
id stockdescription price cnt totalamount
1 Product1 1067 15 16005
1 Product1 1290 103 132870
2 Product2 2750 70 192500
3 Product3 500 0 0
But now i have this 2nd database (database2) with a second inventory table (stock2) (exactly the same structure as database1.table_stock)
How do i alter my query so i can also add 'cnt2' and change total to my results?
Like this:
id stockdescription price cnt cnt2 totalcnt totalamount
1 Product1 1067 15 0 15 16005
1 Product1 1290 103 0 103 132870
2 Product2 2750 70 5 75 206250
3 Product3 500 0 4 4 2000
You can join multiple tables, but you'd get the full join of the two stock tables, which means you'd get wrong counts after the GROUP BY. You can avoid that by nesting your queries, e.g. along these lines:
SELECT sub.*, COUNT(stock2.inkoop) AS cnt2
FROM ( <paste your query here> ) AS sub
LEFT JOIN database2.stock2 AS stock2 ON sub.stockid = stock2.stock_id
GROUP BY sub.stockid
ORDER BY sub.stockid ASC
Now you have two left joins, each with its own GROUP BY. So each left join only sees a single left hand table factor, and you won't get duplicates caused by joining too many tables at once.