aggregation: sum columns by ID and average columns by id (gender and location unchanged) - sql-server-2008

I want to aggregate my data. I want to sum all of of the columns, for a given ID, and average the other column. Here is what I have and what I would like. Also, I need to put this into a new table.
ID Cash charge total proportion gender location
1 3.00 2.00 5.00 .66 m 28972
1 2.00 1.00 3.00 .66 m 28972
1 3.00 0.00 3.00 1 m 28972
1 4.00 2.00 6.00 .66 m 28972
2 3.00 3.00 6.00 .5 f 37352
2 4.00 6.00 10.00 .4 f 37352
This is what I want in a new table. I want to sum the cash, charge, and total for a given ID and I want to average the proportion for a given ID. Gender and location need to be there, but not summed or averaged
ID SumCash Sumcharge Sumtotal AvgProportion Gender Location
1 12.00 5.00 17.00 .745 m 28972
2 7.00 9.00 16.00 .45 f 37352

You can get the result by using the aggregate functions sum() and avg():
select id,
sum(cash) SumCash,
sum(charge) sumCharge,
sum(total) sumTotal,
avg(proportion) avgProportion
from yt
group by id;
See SQL Fiddle with Demo
Edit, with the new columns that you added you can still get the result by using the aggregate functions. You will just need to include the gender and location columns in the GROUP BY clause:
select id,
sum(cash) SumCash,
sum(charge) sumCharge,
sum(total) sumTotal,
avg(proportion) avgProportion,
gender,
location
from yt
group by id, gender, location;
See SQL Fiddle with Demo

Here the query what you need:
SELECT ID, SUM(A.CASH), SUM(A.CHARGE), SUM(A.TOTAL), SUM(A.AVGPROPORTION)/COUNT(ID)
FROM A
WHERE A.ID = ID
GROUP BY A.ID

Related

MySQL - How To query a table result that involves preceding calculated values

Say i have a table items sorted ascending by date
date
item
quantity
cost
2022-12-01
Pencil
12
10.00
2022-12-02
Pencil
10
10.00
2022-12-04
Pencil
5
10.00
2022-12-06
Eraser
10
4.00
2022-12-10
Eraser
50
4.00
2022-12-15
Eraser
25
4.00
I need to write an SQL query that returns a calculated field called calculated_cost, where the expression is simply quantity * cost
Then I will need to increment calculated_cost for every row and save it to a field called accumulated_cost
However here is the challenge, I am also required to store a field called previous_accumulated_cost where it takes the preceding accumulated_cost and store it as a value.
Note that I also need to calculate these by partitioning based on item and order by date, means i need to reset the accumulated_cost and previous_accumulated_cost when I reach a new item.
Basically i need to generate an output like this.
date
item
quantity
cost
calculated_cost
accumulated_cost
previous_accumulated_cost
2022-12-01
Pencil
12
10.00
120.00
120.00
0.00
2022-12-02
Pencil
10
10.00
100.00
220.00
120.00
2022-12-04
Pencil
5
10.00
50.00
270.00
220.00
2022-12-06
Eraser
10
4.00
40.00
40.00
0.00
2022-12-10
Eraser
50
4.00
200.00
240.00
40.00
2022-12-15
Eraser
25
4.00
100.00
340.00
240.00
I have already tried an SQL query like this
SELECT *,
(i.quantity * i.cost) AS calculated_cost,
SUM(i.quantity * i.cost) OVER (PARTITION BY i.item ORDER BY i.date) AS accumulated_cost,
IFNULL(LAG(i2.accumulated_cost) OVER (PARTITION BY i.item ORDER BY i.date), 0) AS previous_accumulated_cost
FROM items i
LEFT JOIN (
SELECT item, SUM(quantity * cost) OVER (PARTITION BY item ORDER BY date) AS accumulated_cost
FROM items
) i2 ON i.item = i2.item
However this doesn't work, as the number of item entries can keep increasing and I am not sure how to keep referencing back the previous_accumulated_cost
Would appreciate some help. Thanks!
Your hunch to use analytic functions was spot on. I would suggest using this version:
SELECT
quantity * cost AS calculated_cost,
SUM(quantity * cost) OVER (PARTITION BY item ORDER BY date) AS accumulated_cost,
SUM(quantity * cost) OVER (PARTITION BY item ORDER BY date) - (quantity * cost) AS previous_accumulated_cost
FROM items
ORDER BY item, date;
Appreciate that the previous_accumulated_cost is simply the accumulated_cost minus the calculated_cost.

How to calculate price average while grouping by date in MySQL?

In MySQL 5.7 I need to calculate the average discount per merchant and day.
There are 2 tables:
produts_manufacturers:
PROD_ID | MANUFACTURER_ID | PRICE_RECOM
1 1 10
2 1 20
merchants_prices
PROD_ID | MERCHANT_ID | PRICE_ACTUAL | DATE
1 10 9.00 21-01-20
1 11 8.80 21-01-20
1 11 9.00 22-01-19
My goal is a chart that gets its metric value from group by DATE, merchant_id
Now how is it possible to calculate the average discount of all products from a manufacturer at a particular merchant without also grouping by PROD_ID?
SELECT
date,
merchant_id,
1- (t.PRICE_ACTUAL / p.PRICE_RECOM)*100 AS discount2
-- (1 - ROUND(AVG(PRICE_ACTUAL),2) / p.PRICE_RECOM)*100 AS discount
FROM
merchants_prices t
INNER JOIN produts_manufacturers p ON t.PROD_ID = p.PROD_ID
WHERE
p.MANUFACTURER_ID = 1
AND PRICE_ACTUAL IS NOT NULL
GROUP by
date,
MERCHANT_ID
ORDER BY
date desc, merchant_id
To calculate average discount per merchant and day:
SELECT `DATE`, MERCHANT_ID, ROUND(AVG(discount), 2) as discount
FROM (
SELECT mp.`DATE`, mp.MERCHANT_ID, 1- (mp.PRICE_ACTUAL / pm.PRICE_RECOM)*100 AS discount
FROM produts_manufacturers pm
JOIN merchants_prices mp ON mp.PROD_ID = pm.PROD_ID
-- WHERE pm.MANUFACTURER_ID = 1 -- If you want to restrict to a specific manufacturer
) as x
GROUP BY `DATE`, MERCHANT_ID;
With your dataset ->
DATE MERCHANT_ID discount
2021-01-20 10 -89
2021-01-20 11 -87
2022-01-19 11 -89
To help you I made a fiddle here

Order mysql fields from several tables

I need to achieve the following and having an issue in doing so.
Here's the situation:
product
-----------------------------
id sku is_top name
-----------------------------
1 aaa 1 Item 1
2 bbb 0 Item 2
3 ccc 1 Item 3
4 ddd 1 Item 4
5 eee 1 Item 5
product_price
-----------------------------
product_id price type
-----------------------------
1 1.23 regular
1 1.01 special
2 3.34 regular
3 3.45 regular
4 2.67 regular
5 5.55 regular
product_wholesale_price
-----------------------------
product_id price minimum_count
-----------------------------
1 1.12 10
1 0.95 25
2 2.12 40
3 3.00 40
5 4.00 30
product_special_price
-----------------------------
product_id price customer_id
-----------------------------
1 1.00 7
2 2.00 20
3 2.50 45
Ordering needs to be like this:
Products with is_top = 1 and has a record in product_price with
type = 'special'
Products with is_top = 1 and no special price
record
All other products
Also ordered by price in descending
order, using the highest price available for a product. For example,
product with id = 1 has the following prices: 1.23, 1.01, 1.12,
1.00. We need to order using the highest, which in this case is 1.23.
So the desirable result order would be this:
Item 1 with price 1.23 (is top and has special price)
Item 5 wit price 5.55 (is top)
Item 3 with price 3.45 (is top)
Item 4 with price 2.67 (is top)
Item 2 with price 3.34 (no top, no special price)
Is something like that even possible in a single query?
Use this:
ORDER BY (is_top = 1 AND type = 'special') DESC, is_top DESC, price DESC
When a condition is true, the value is 1, otherwise 0, so using a condition expression as a DESC ordering criteria puts the rows that match the criteria first.
SELECT p.id, p.name, MAX(pp.price) FROM product p
INNER JOIN product_price pp
ON p.id=pp.product_id
LEFT OUTER JOIN product_special_price psp
ON p.id=psp.product_id
GROUP BY p.id, p.name
ORDER BY MAX(p.is_top AND pp.type='special') DESC,
MAX(p.is_top AND psp.price IS NULL) DESC,
MAX(pp.price) DESC;
Also if you want greatest price from several different columns, in select (and also in ORDER BY) instead of MAX(pp.price) you can write something like GREATEST(MAX(pp.price), MAX(COALESCE(psp.price,0))).

MySQL: Get total hours, then multiply with rate, then rounding in one SELECT statement

My data looks like this:
UserID Hours BillRate
1 1.50 2.25
1 2.50 3.25
1 3.50 3.25
2 5.50 4.25
2 6.50 5.25
2 7.50 5.25
Is there anyway that I can get total spend for each person in one SELECT statement?
This is what I have. It returns what I want, but I have to do 2 SELECT statements.
SELECT UserID, SUM(OneSpend) AS TotalSpend
FROM (
SELECT UserID, ROUND(SUM(Hours)*BillRate,2) AS OneSpend
FROM mytable
GROUP BY UserID, BillRate
) a
GROUP BY UserID
SELECT UserID, ROUND(SUM(Hours*BillRate), 2) AS TotalSpend
FROM mytable
GROUP BY UserID
According to the distributive property of multiplication over addition, SUM(Hours)*BillRate is the same as SUM(Hours * BillRate) when all the BillRate values are the same, as they are when you group by BillRate.

How to (MySQL) multiply columns and then the sum rows?

I've got this table:
id | payment_id | quantity | unit cost
1 633 1 750
2 633 1 750
3 632 2 750
4 632 2 750
What I need is :
payemnt_id | total
633 1500
632 3000
You can also think of this as Countries and then you are trying to find the total for each Country. I was sure there were some tutorials like this but could not find by STFW.
You can simply put the formula (expression) inside SUM:
SELECT payment_id, SUM(`unit cost` * quantity) AS total
FROM myTable
GROUP BY payment_id
SELECT
payment_id,
SUM(subtotal) AS total
FROM(
SELECT
payment_id,
(unit_cost * quantity) AS subtotal
) AS t1
GROUP BY
payment_id
SELECT payemnt_id, SUM(`unit cost` * quantity) as total
FROM Table1
GROUP BY payemnt_id
SELECT COALESCE (SUM(cost_field * quantity_field),0) AS tot FROM Table_Name
I Think This One Is Good, Why ?
Because If Their is No Result It Will Give You Zero