Calculating the sum of quantity * unit price in mysql - mysql

I think I'm missing a simple step here but I can't seem to figure it out. I've read the other threads and they talk about grouping but I can't seem to put it all together right.
I have a simple table that holds inventory transactions. In each row, there is a quantity and a price. I want to get the sum of the quantity and the sum of the each price * each quantity.
Here's my query. If I remove the grouping, I get 1 result that is multiplied by the number of rows in the table. If I add the grouping, I get the correct result multiple times. Am I missing something here? I just feel like running a query to get 20k results when they all contain the same data would be pointless.
SELECT (SUM(i.quantity) - IFNULL(SUM(s.quantity), 0)) AS quantity,
SUM(i.unitprice * i.quantity) AS totalprice
FROM 02_01_transactions t
LEFT JOIN 02_01_transactions i
ON i.type = 1
AND i.active = 1
LEFT JOIN 02_01_transactions s
ON s.type = 2
AND s.active =1
GROUP BY t.id

Not sure there is a need for the joins (you are not joining on any common value) or the type = 2 rows if you are just subtracting them out. Is there a reason the following does not work?
-- Total quantity, total price of all type 1, active transactions.
SELECT SUM(quantity) AS quantity,
SUM(unitprice * quantity) AS totalprice
FROM 02_01_transactions
WHERE type = 1
AND active = 1

Here's my guess at what you were trying to accomplish:
select
sum(quantity * case type when 1 then 1 when 2 then -1 end) as quantity,
sum(unitprice * quantity) as totalprice
from 02_01_transactions
where type in (1, 2) and active = 1

Related

Mysql - most efficient way to retrieve data based on multiple selects and wheres

I'm having trouble finding the most efficient way of retrieving various different sumed values from a Mysql table.
Let's say I've got 4 columns - userid, amount, paid, referral.
I'd like to retrieve the following based on a user id:
1 - the sum of amount that is paid (marked as 1)
2 - the sum of amount that is unpaid (marked as 0)
3 - the sum of amount that is paid and referral (marked as 1 on both paid and referral columns)
4 - the sum of amount that unpaid and referral (marked as 0 on paid and 1 on referral columns)
I've tried an embedded select statement like this:
SELECT (
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and userid = '100'
) AS unpaid
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and userid = '100'
) AS paid,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and isreferral = 1 and userid = '100'
) AS refpending,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and isreferral = 1 and userid = '100'
) AS refpaid
This works, but its slow (or at least feels like it could be quicker) on my server, around 1.5 seconds.
I'm sure there is a better way of doing this with a group statement but can't get my head around it!
Any help is much appreciated.
Thanks
You can use conditional expressions inside SUM():
SELECT
SUM(CASE WHEN ispaid=0 THEN payout END) AS unpaid,
SUM(CASE WHEN ispaid=1 THEN payout END) AS paid,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpending,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpaid
FROM table1
WHERE userid = '100'
If a given row is not matched by any CASE...WHEN clause, then the value of the expression is NULL, and SUM() ignores NULLs. You could also have an ELSE 0 clause in there if you want to be more explicit, since SUM() will not be increased by a 0.
Also make sure you have an index on userid in this table to select only the rows you need.

MySQL most price change over time

price | date | product_id
100 | 2020-09-21 | 1
400 | 2020-09-20 | 2
300 | 2020-09-20 | 3
200 | 2020-09-19 | 1
400 | 2020-09-18 | 2
I add an entry into this table every day with a product's price that day.
Now I want to get most price drops for the last week (all dates up to 2020-09-14), in this example it would only return the product_id = 1, because that's the only thing that changed.
I think I have to join the table to itself, but I'm not getting it to work.
Here's something that I wanted to return the most price changes over the last day, however it's not working.
select pt.price, pt.date, pt.product_id, (pt.price - py.price) as change
from prices as pt
inner join (
select *
from prices
where date > '2020-09-20 19:33:43'
) as py
on pt.product_id = py.product_id
where pt.price - py.price > 0
order by change
I understand that you want to count how many times the price of each product changed over the last 7 days.
A naive approach would use aggregation and count(distinct price) - but it fails when a product's price changes back and forth.
A safer approach is window functions: you can use lag() to retrieve the previous price, and compare it against the current price; it is then easy to aggregate and count the price changes:
select product_id, sum(price <> lag_price) cnt_price_changes
from (
select t.*, lag(price) over(partition by product_id order by date) lag_price
from mytable t
where date >= current_date - interval 7 day
) t
group by product_id
order by price_changes desc
Try using MAX() and MIN() instead....
select MAX(pt.price), MIN(pt.price), MAX(pt.price) - MIN(pt.price) as change
from prices as pt
inner join (
select *
from prices
where date > '2020-09-20 19:33:43'
) as py
on pt.product_id = py.product_id
order by change
Instead of subtracting every row by every other row to get the result, you can find the max and min's easily by means of MAX() and MIN(), and, ultimately, **MAX() - MIN()**. Relevant lines from the linked MySQL documentation...
MAX(): Returns the maximum value of expr.
MIN(): Returns the minimum value of expr.
You won't be able to pull the other fields (id's, dates) since this is a GROUP BY() implied by the MAX() and MIN(), but you should then be able to get that info by query SELECT * FROM ... WHERE price = MAX_VALUE_JUST_ACQUIRED.
This examples will get you results per WeekOfYear and WeekOfMonth regarding the lowering of the price per product.
SELECT
COUNT(m1.product_id) as total,
m1.product_id,
WEEK(m1.ddate) AS weekofyear
FROM mytest m1
WHERE m1.price < (SELECT m2.price FROM mytest m2 WHERE m2.ddate<m1.ddate AND m1.product_id=m2.product_id LIMIT 0,1)
GROUP BY weekofyear,m1.product_id
ORDER BY weekofyear;
SELECT
COUNT(m1.product_id) as total,
m1.product_id,
FLOOR((DAYOFMONTH(ddate) - 1) / 7) + 1 AS weekofmonth
FROM mytest m1
WHERE m1.price < (SELECT m2.price FROM mytest m2 WHERE m2.ddate<m1.ddate AND m1.product_id=m2.product_id LIMIT 0,1)
GROUP BY weekofmonth,m1.product_id
ORDER BY weekofmonth;
Try this out in SQLFiddle.

Calculate a ratio from two MySQL SELECT statements

I have a simple inventory table listing unique items, each record having one of a set of "Item_code". I would like to calculate the percentage of items sold in each Item_code group.
Easy enough to do in 3 steps in PHP, but I cannot figure out how to do it in one statement. Is it possible?
(edited to add the sum(Price) portion.)
1)
Select Item_code, count(*), sum(Price) as value1
From Inventory
group
by Item_Code
2)
Select Item_Code, count(*) , sum(Price) as value2
from Inventory
WHERE Status like "Sold"
group
by Item_code
3) Percent sold = (2) / (1), for each Item_code
Percent value sold = Value2 / Value1
The result should be of the form:
Item Code / Number Listed / Number sold / Percentage / Value listed / Value Sold / Percent Value Sold
count ignores nulls. Thus, you can use a case expression to count the number of items sold without having to use a where clause, and from there on getting the percentage is easy:
SELECT item_code,
COUNT(*) AS listed,
COUNT(CASE status WHEN 'Sold' THEN 1 END) AS sold,
COUNT(CASE status WHEN 'Sold' THEN 1 END) * 100.0 / COUNT(*) AS percentage
FROM inventory
GROUP BY item_code

MS SQLServer How to multiply two columns, then add them all together..?

I'm new here. First post. I'd really appreciate some help.
I'm trying to calculate total sales for all products sold.
I have a Quantity column and a Price column.
I understand how to multiply these two columns, BUT I do not know how to add them all together in the same query.
Here is an example:
Quantity: 2, 3, 1 Price: 2, 4, 5
I could do Quantity * Price to get: 4, 12, 5
But then how would I add 4 + 12 + 5 to get the total? I need this step to be included in the same query.
EDIT: Both the Quantity and Price columns are in the same table.
SALES (Quantity, Price)
I am using Microsoft SQL-Server.
Example if you have one table:
SELECT dbo.orderid,
SUM(dbo.quantity * dbo.price) AS grand_total,
FROM ORDERITEM
If you have two tables instead of one, then:
SELECT oi.orderid,
SUM(oi.quantity * p.price) AS grand_total,
FROM ORDERITEM oi
JOIN PRODUCT p ON p.id = oi.productid
WHERE oi.orderid = #OrderId
GROUP BY oi.orderid
Adding all the rows (orderid numbers) up together to get a total, you would simply groupby and them select the sum value. Example below:
SELECT Orderid, SUM(quanity) AS Expr1, SUM(price) AS Expr2, SUM(quanity * price) AS Total
FROM dbo.mytable
GROUP BY pid
HAVING (pid = 2)
Or this in a SQL view showing the total QTY and Price:
SELECT Orderid, SUM(quanity) AS Quanity, SUM(price) AS Price, SUM(quanity * price) AS Total
FROM dbo.mytable
GROUP BY pid

Mysql- Aggregate function query grouping problem

Consider following table.
I'm trying to write a query to display - Max values for all the parts per category. Also display the date when the value was max.
So i tried this -
select Part_id, Category, max(Value), Time_Captured
from data_table
where category = 'Temperature'
group by Part_id, Category
First of all, mysql didn't throw an error for not having Time_Captured in group by.
Not sure if its a problem with mysql or my mysql.
So I assume it should return -
1 Temperature 50 11-08-2011 08:00
2 Temperature 70 11-08-2011 09:00
But its returning me the time captured from the first record of the data set i.e. 11-08-2011 07:00
Not sure where I'm going wrong. Any thoughts?
(Note: I'm running this inside a VM. Just in case if it changes anything)
You need to join to the results of a query that finds the max(value), like this:
select dt.Part_id, dt.Category, dt.Value, dt.Time_Captured
from data_table dt
join (select Part_id, Category, max(Value) as Value
from data_table group by 1, 2) x
on x.Part_id = dt.Part_id and x.Category = dt.Category
where dt.category = 'Temperature';
Note that this will return multiple rows if there are multiple rows with the same max value.
If you want to limit this to one row even though there are multiple matches for max(value), select the max(Time_Captured) (or min(Time_Captured) if you prefer), like this:
select dt.Part_id, dt.Category, dt.Value, max(dt.Time_Captured) as Time_Captured
from data_table dt
join (select Part_id, Category, max(Value) as Value
from data_table group by 1, 2) x
on x.Part_id = dt.Part_id and x.Category = dt.Category
where dt.category = 'Temperature'
group by 1, 2, 3;