Sum columns with similar value- SQL - mysql

I need to sum all fields that have similar value.
I have a simple SQL query that give me back this result:
For example, the name like 'Climatizzazione' has to be sum to 'Climatizzatori Samsung' and 'Climatizzatori Daiki' and get a unique result.
The final result would be like that:
| name | totale_fatturato |
| -------- | -------------- |
| Climatizzazione | 535.241,583465|
| Scaldabagni| 90680,77684|
| Differenziali e Magnetotermici| 78511,185704|
ecc.......
This is my SQL query:
SELECT
cl.name,
SUM(od.total_price_tax_excl) AS totale_fatturato
FROM `ww_ps_order_detail` AS `od`
INNER JOIN `ww_ps_product` AS p ON od.product_id = p.id_product
INNER JOIN `ww_ps_category_lang` AS cl ON p.id_category_default = cl.id_category
WHERE od.ID_ORDER IN (
SELECT ID_ORDER
FROM ww_ps_orders
WHERE 1=1 AND DATE_ADD >= DATE_SUB(NOW(), INTERVAL 30 DAY)) AND cl.id_lang = 1
GROUP BY name
ORDER BY totale_fatturato DESC
LIMIT 10
What i have to do for get the result i want? Thx!

Thanks to Akina, Jonas Metzler and Trillion, i found my solution.
So, how you have suggest me, i create a supplementary column with some cases where i can handle all the exceptions and group by this column.
This is my result:
SELECT
cl.name AS NAME,
SUM(od.total_price_tax_excl) AS `totale_fatturato`,
CASE
WHEN cl.name LIKE 'Climatizza%' THEN 'Climatizzazione'
/* SOME OTHER CASES */
ELSE cl.name
END AS groupName
FROM `ww_ps_order_detail` AS `od`
INNER JOIN `ww_ps_product` AS p ON od.product_id = p.id_product
INNER JOIN `ww_ps_category_lang` AS cl ON p.id_category_default = cl.id_category
WHERE od.ID_ORDER IN (
SELECT ID_ORDER
FROM ww_ps_orders
WHERE 1=1 AND DATE_ADD >= DATE_SUB(NOW(), INTERVAL 30 DAY)) AND cl.id_lang = 1
GROUP BY groupName
ORDER BY totale_fatturato DESC

Related

Query to group without lost IF function

I created a query to search for all my stock products that are in orders placed, and I created an alias "total_vendido" that adds the products when they are kits or units, so far this is ok. But now I need to group the sizes and add this "total_vendido" alias by size.
Query:
SELECT `gp`.`id`, `gp`.`data`, `gp`.`status`, `gp`.`situacao`, `gp`.`nome`,
`gp`.`razao_social`, `gp`.`email`, `gp`.`telefone`,
`itens`.*,
IF(itens.tipo = 'K',
SUM(itens.qtde_prod) * itens.qtde_lote,
SUM(itens.qtde_prod)
) AS total_vendido,
`estoq`.`titulo`
FROM `ga845_pedidos_view` `gp`
JOIN `ga845_pedido_itens` `itens` ON `itens`.`pedido_id` = `gp`.`id`
JOIN `ga845_produtos` `prod` ON `prod`.`id` = `itens`.`produtos_id`
JOIN `ga845_produtos_estoque` `estoq` ON `estoq`.`id` = `prod`.`estoques_id`
WHERE `gp`.`situacao` IN('Pedido Realizado', 'Pagamento Aprovado',
'Pedido em Separação', 'Pedido Separado')
AND date(gp.data) >= '2020-07-25'
AND date(gp.data) <= '2020-07-25'
AND `estoq`.`id` IN('24')
GROUP BY `itens`.`tamanho_prod`, `estoq`.`id`
ORDER BY `estoq`.`id` ASC, `itens`.`tamanho_prod` ASC
Current result (only important columns)
tamanho_prod | tipo | total_vendido
G | K | 5
G | U | 1
M | K | 1
P | U | 8
Expected result (only important columns)
tamanho_prod | total_vendido
G | 6
M | 1
P | 8
Code related to Expected result (only important columns)
SELECT
, `itens`.`tamanho_prod`
, SUM( IF(itens.tipo = 'K',
itens.qtde_prod * itens.qtde_lote,
itens.qtde_prod
) AS total_vendido
FROM `ga845_pedidos_view` `gp`
JOIN `ga845_pedido_itens` `itens` ON `itens`.`pedido_id` = `gp`.`id`
JOIN `ga845_produtos` `prod` ON `prod`.`id` = `itens`.`produtos_id`
JOIN `ga845_produtos_estoque` `estoq` ON `estoq`.`id` = `prod`.`estoques_id`
WHERE `gp`.`situacao` IN('Pedido Realizado', 'Pagamento Aprovado',
'Pedido em Separação', 'Pedido Separado')
AND date(gp.data) >= '2020-07-25'
AND date(gp.data) <= '2020-07-25'
AND `estoq`.`id` IN('24')
GROUP BY `itens`.`tamanho_prod`
ORDER BY `itens`.`tamanho_prod` ASC
if you want an aggregated result just for itens.tamanho_prod .. then you should use group by only for this column ... and move the SUM() outside the if condition

How to calculate percent increase/decrease using previous value

I have a query that returns total value of sales grouped by month. I would like to add a column that returns the growth/decrease in percentage comparing with previous rows.
I have tried already to use CREATE TEMPORARY TABLE, creating a variable #var :=, but nothing is really working. Ideally my result would be:
Month | Sales | Perc
1 | 100 | 0
2 | 150 | 50
3 | 100 | -33.33
The calculation to be done is: ((actual_value - previous_value) / previous_value) *100
About the tables, I working with sales, products, sales_items, so my query to retrieve the total amount of sales grouped by month is:
SELECT
MONTH(s.sale_date) AS Month,
SUM(p.retail_price * si.quantity) AS Sales_Amount
FROM sales s
INNER JOIN sales_items si ON s.sale_id = si.sale_id
INNER JOIN products p ON si.product_id = p.product_id
WHERE YEAR(s.sale_date) = '2018'
GROUP BY month
ORDER BY month;
As I'm using SUM to summarise the items of the sales and aggregating that into each sale_id, and after grouping by month, it seems complicated to use that value into a new column, so it would be great if someone has some idea how to do it.
In MySQL 8.0, you can turn the aggregate query to a subquery and use window function LAG to access the value of the previous month, like:
SELECT
Sales_Month,
Sales_Amount,
( Sales_Amount - LAG(Sales_Amount) OVER(ORDER BY Sales_Month) )
/LAG(Sales_Amount) OVER(ORDER BY Sales_Month) * 100 AS Percent_Increase
FROM (
SELECT
MONTH(s.sale_date) AS Sales_Month,
SUM(p.retail_price * si.quantity) AS Sales_Amount
FROM sales s
INNER JOIN sales_items si ON s.sale_id = si.sale_id
INNER JOIN products p ON si.product_id = p.product_id
WHERE YEAR(s.sale_date) = '2018'
GROUP BY Sales_Month
) x
ORDER BY Sales_Month
You can add a new column "PrevMonthSales". To do that you have to join your query with itself :
SELECT ...
FROM
(...your_query...) s1
LEFT JOIN (...your_query...) s2 ON s2.Month = s1.Month - 1
In your case:
SELECT s1.Month, s1.Sales_Amount,
COALESCE(s2.Sales_Amount, 0) "PrevMonthSales",
CASE
WHEN s1.Sales_Amount = 0 THEN 0
ELSE (s1.Sales_Amount - COALESCE(s2.Sales_Amount, 0)) / s1.Sales_Amount
END "Percent"
FROM
(...your_query...) s1
LEFT JOIN (...your_query...) s2 ON s2.Month = s1.Month - 1
Make below a temp table called month_sales
SELECT
MONTH(s.sale_date) AS Month,
SUM(p.retail_price * si.quantity) AS Sales_Amount
FROM sales s
INNER JOIN sales_items si ON s.sale_id = si.sale_id
INNER JOIN products p ON si.product_id = p.product_id
WHERE YEAR(s.sale_date) = '2018'
GROUP BY month
ORDER BY month;
Query to find month over month difference is :
SELECT *,
case
when m2.Sales_Amount is null then 0
else (m2.Sales_Amount - m1.Sales_Amount)/m1.Sales_Amount
end as Perc
FROM month_sales m1
left Join month_sales m2
WHERE m1.month = m2.month - 1

Mysql subquery issues

Here is my mysql schema and query.
http://sqlfiddle.com/#!2/73b0d/2
I want sum(each day's memo.discount), date, sum(each day's sale sum(item.sell_price)) in each row. But can't seem to find out the way. How can I do this?
Expected outcome.
total_discount | added_on | total_sale
300 | 2014-06-25 00:00:00 | 1580
230 | 2014-06-26 00:00:00 | 980
Thanks in advance.
SELECT
SUM(m.discount) AS total_discount,
m.added_on,
sub0.total_sold AS total_sale
FROM memo m
LEFT OUTER JOIN
(
SELECT DATE(memo.added_on) AS group_added_on, SUM(item.sell_price) AS total_sold
FROM memo
JOIN memo_item ON memo_item.memo_id = memo.id
JOIN item ON item.id = memo_item.item_id
WHERE memo.showroom_id = 2
GROUP BY group_added_on
) sub0
ON group_added_on = DATE(m.added_on)
WHERE m.showroom_id = 2 and m.added_on BETWEEN '2014-06-25' AND '2014-06-26'
GROUP BY m.added_on
This has a sub query that gets the sum of the selling prices for each day for the showroom_id you are interested in, then joins that back against the memo table.
How about this?
select
sum(m.discount) as total_discount,
m.added_on,
sum(item.sell_price) as total_sale
from memo m
join memo_item on memo_item.memo_id = m.id
join item on item.id = memo_item.item_id
where m.showroom_id = 2 and m.added_on between '2014-06-25' and '2014-06-26'
group by m.added_on
Edit: to use discount only from "memo" table... :
select
sum(discount) as total_discount,
added_on,
sum(subtotal_sale) as total_sale
from
(
select
m.discount,
m.added_on,
sum(item.sell_price) as subtotal_sale
from memo m
join memo_item on memo_item.memo_id = m.id
join item on item.id = memo_item.item_id
where m.showroom_id = 2 and m.added_on between '2014-06-25' and '2014-06-26'
group by m.id
) h
group by added_on

Sum of columns from tables in join

I have 3 tables, Orders, Orders_products and Orders_total. Currently i have a query that gets the SUM of products for each months, but now we would like to also add the freight cost that is in a different table.
I tried with the following that returned the correct total_value, but the total_shipping is 5 times as big. This i think has to due with that orders, can have multiplie products, but i cant figure out what else to do.
SELECT Count(DISTINCT O.orders_id) AS Orders,
Sum(OP.final_price * OP.products_quantity) AS total_value,
Date_format(O.last_modified, '%m-%Y') AS date_interval,
Sum(OT.value) AS total_shipping
FROM
orders AS O
LEFT JOIN
orders_total AS OT
ON ( OT.orders_id = O.orders_id
AND OT.class = 'ot_shipping' ),
orders_products AS OP
WHERE
( O.orders_id = OP.orders_id )
AND ( O.orders_status = 3 )
GROUP BY date_interval
ORDER BY O.last_modified DESC
The returned value is:
+----+------------+---------------+----------------+
| ID | total_value| date_interval | total_shipping |
+----+------------+---------------+----------------+
| 17 | 55912.2160 | 01-2014 | 24954 |
Expected:
+----+------------+---------------+----------------+
| ID | total_value| date_interval | total_shipping |
+----+------------+---------------+----------------+
| 17 | 55912.2160 | 01-2014 | 4938 |
Here is the sqlfiddle http://sqlfiddle.com/#!2/dfe10/1/0
It contains one order, with 3 products in it. the expected total_value is 500 and the expected total_shipping is also 500, but returns 1500 (3 x products). Sadly i had to remove a lot of fields from my table due to a limit in sqlfiddle of max 8000 chars.
Try putting the shipping value into an inline view:
select count(*) as Orders,
sum(ord.order_total_value) as total_value,
ord.date_interval as date_interval,
sum(ship.order_shipping_value) as total_shipping
from
(
SELECT O.orders_id,
O.last_modified AS modified_date,
Sum(OP.final_price * OP.products_quantity) as order_total_value,
Date_format(O.last_modified, '%m-%Y') as date_interval
FROM orders AS O
INNER JOIN orders_products AS OP on O.orders_id = OP.orders_id
WHERE O.orders_status = 3
GROUP BY date_interval,O.orders_id
) ord LEFT OUTER JOIN
(
SELECT orders_id,sum(value) as order_shipping_value
FROM orders_total
WHERE class='ot_shipping'
GROUP BY orders_id
) ship ON ord.orders_id = ship.orders_id
GROUP BY ord.date_interval
ORDER BY modified_date DESC;

Correct SQL statement needed in my scenario

I'm having a problem in having my desired result in my database. I want to extract Total Row Count from other table where in it's condition will be belong to the other table. To make it clear, Here is the sample illustration.
>tblBus
>
>Bus ID ~ Day~ Type
>
>1000 | Monday | Public
>2000|Monday | Private
>3000|Tuesday| Public
>4000|Monday | Public
>tblReservation
>
>Bus ID | Date
>1000 | 2013/3/4
>2000 | 2013/3/4
>3000 | 2013/3/6
Let say that the reservation day would be on Monday and that is 2013/3/4.. I want to display all PUBLIC buses that is available on Monday with a new row that has the total number of reservation made on that bus.
e.g.
GeneratedTable (WHERE Date ='2013/3/4', Type='Public', Day='Monday')
>Bus ID | Day | Type | TotalNumberReservation
>1000 |Monday | Public | 1
>4000 |Monday | Public | 1
You can use the following which joins your tables on the bus id and then gets a count of the reservations:
select b.`bus id`,
b.day,
b.type,
count(r.date) TotalNumberReservation
from tblBus b
inner join tblReservation r
on b.`bus id` = r.`bus id`
where r.date = '2013-03-04'
and b.day = 'Monday'
group by b.`bus id`, b.day, b.type
See SQL Fiddle with Demo
If you want to return all rows that match the correct day even if there is not a reservation, then you will want to use a LEFT JOIN:
select b.`bus id`,
b.day,
b.type,
count(r.date) TotalNumberReservation
from tblBus b
left join tblReservation r
on b.`bus id` = r.`bus id`
AND r.date = '2013-03-04'
where b.day = 'Monday'
group by b.`bus id`, b.day, b.type
See SQL Fiddle with Demo
Here is the basic query to generate the counts for all busses, days, and dates that you can then filter as you need:
Select a.bus_id, day, type, count(*) as TotalNumberReservation
from tblBus a
join tblReservation b
on a.busId=b.busId
group by a.bus_id,day,type