Query to group without lost IF function - mysql

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

Related

Sum columns with similar value- SQL

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

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;

How to query and group every continuous number series in MySQL?

I have this freight.or_nos table which contains series of receipt numbers. I want to list all the or's being issued excluding the status='Cancelled' making the series broken in groups.
For example I have this receipt stab 125001-125050, and 125020 is cancelled so the listing result would be:
+-------------------------------------------------------+
| OR Start | OR End | Quantity | Amount |
+-------------------------------------------------------+
| 125001 | 125019 | 19 | |
+-------------------------------------------------------+
| 125021 | 125050 | 30 | |
+-------------------------------------------------------+
This seems to be a tough query.
Thanks for reading but I already made it, just now! :)
Here's my query(disregard the other characters it's form our CGI):
{.while SELECT `start`,`end`,or_prefix,or_suffix,SUM(a.amount) AS g_total,COUNT(*) AS qcount FROM (SELECT l.id AS `start`,( SELECT MIN(a.id) AS id FROM ( SELECT a.or_no AS id FROM freight.`or_nos` a WHERE a.status!='Cancelled' AND a.log_user = 0#user_teller AND DATE(a.or_date)='#user_date`DATE' AND IF(a.status='Default' AND a.amount=0,0,1) ) AS a LEFT OUTER JOIN ( SELECT a.or_no AS id FROM freight.`or_nos` a WHERE a.status!='Cancelled' AND a.log_user = 0#user_teller AND DATE(a.or_date)='#user_date`DATE' AND IF(a.status='Default' AND a.amount=0,0,1) ) AS b ON a.id = b.id - 1 WHERE b.id IS NULL AND a.id >= l.id ) AS `end` FROM ( SELECT a.or_no AS id FROM freight.`or_nos` a WHERE a.status!='Cancelled' AND a.log_user = 0#user_teller AND DATE(a.or_date)='#user_date`DATE' AND IF(a.status='Default' AND a.amount=0,0,1) ) AS l LEFT OUTER JOIN ( SELECT a.or_no AS id FROM freight.`or_nos` a WHERE a.log_user = 0#user_teller AND DATE(a.or_date)='#user_date`DATE' AND IF(a.status='Default' AND a.amount=0,0,1) ) AS r ON r.id = l.id - 1 WHERE r.id IS NULL) AS k LEFT JOIN freight.`or_nos` a ON a.`or_no` BETWEEN k.start AND k.end AND DATE(a.`or_date`)='#user_date`DATE' AND a.log_user =0#user_teller AND IF(a.status='Default' AND a.amount=0,0,1) AND a.status!='Cancelled' GROUP BY `start`}
{.start}{.x.24.12:end}{.x`p0.40.-5:qcount}{.x`p2.57.-15:g_total}{.asc 255}
{.wend}{.asc 255}

My SQL query is failing to get low cost rooms at multiple rooms bookings

Bellow is my "rooms" mysql table. (This is example table i have created to show here.)
I want to show low cost rooms in case multiple room bookings. Ex: User have select two room, 1 adult in first room and 2 adults in second room. Now my result should come as below
My Query is : SELECT * FROM rooms WHERE hotel_code="100" GROUP BY adult+child Order by cost ASC
It is not working. I am not able to get the expected result with this query. Please let me know the solution for this.
Try this:
SELECT r.*
FROM Rooms r
INNER JOIN
(
SELECT
adult, child, MIN(Cost) MinCost
FROM Rooms
WHERE hotel_code = 100
GROUP BY adult, child
) m ON r.adult = m.adult AND r.child = m.child
AND r.cost = m.mincost
ORDER BY r.id
LIMIT 2;
SQL Fiddle Demo
This will give you:
| ID | HOTEL_CODE | ROOM_TYPE | ADULT | CHILD | COST |
---------------------------------------------------------
| 2 | 100 | Single Delux | 1 | 0 | 20 |
| 3 | 100 | Twin Stadard | 2 | 0 | 25 |
Extending Mahmoud's thinking with a (less scalable) extension...
SELECT a.*
FROM
( SELECT x.*
FROM rooms x
JOIN
( SELECT hotel_code
, adult
, child
, MIN(cost) min_cost
FROM rooms
GROUP
BY hotel_code
, adult
, child
) y
ON y.hotel_code = x.hotel_code
AND y.adult = x.adult
AND y.child = x.child
AND y.min_cost = x.cost
) a
LEFT
JOIN
( SELECT x.*
FROM rooms x
JOIN
( SELECT hotel_code
, adult
, child
, MIN(cost) min_cost
FROM rooms
GROUP
BY hotel_code
, adult
, child
) y
ON y.hotel_code = x.hotel_code
AND y.adult = x.adult
AND y.child = x.child
AND y.min_cost = x.cost
) b
ON b.hotel_code = a.hotel_code
AND b.adult = a.adult
AND b.child = a.child
AND b.cost = a.cost
AND b.id < a.id
WHERE b.id IS NULL;

difficulties getting a 3 table join to return expected results

I'm having some difficulty getting to the bottom of this sql query.
Tables:
--Tickets-- --Finance-- --Access--
id_tickets id_finance id_access
name_tickets id_event id_event
cat_tickets id_tickets id_tickets
sold_finance scan_access
Finance and Access both contain a row for multiple of each ticket type as listed in tickets.
and I'm trying to get:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 3043 | 2571
season | 481 | 292
comp | 114 | 75
-------------------------------------
total | 3638 | 2938
The closest I've been to the result I've used:
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance INNER JOIN tickets ON finance.id_tickets = tickets.id_tickets
INNER JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235 AND finance.id_event = access.id_event
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
but that just returns:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 4945 | 4437
season | 954 | 599
comp | 342 | 375
-------------------------------------
total | 6241 | 5411
Any ideas where I could be going wrong?
Thanks!
The problem is the relation between access and finance tables, you have to join them. Even if you LEFT JOIN the table the predicate finance.id_event = access.id_event will make it INNER JOIN. As a work around, use UNION like this:
SELECT
tickets.cat_tickets,
SUM(CASE WHEN a.Type = 'f' THEN num ELSE 0 END) AS total_sold,
SUM(CASE WHEN a.Type = 'a' THEN num ELSE 0 END) AS total_scan
FROM tickets
LEFT JOIN
(
SELECT 'f' Type, id_tickets, sold_finance num
FROM finance f
WHERE id_event = 1
UNION ALL
SELECT 'a', id_tickets, scan_access
FROM access
WHERE id_event = 1
) a ON a.id_tickets = tickets.id_tickets
GROUP BY tickets.cat_tickets;
SQL Fiddle Demo
Although I am fully clear on what you want, just try this query if the result of this is what you are expecting.
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance LEFT JOIN tickets ON finance.id_tickets = tickets.id_tickets
LEFT JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
Disclaimer: This query is not tested due to incomplete data on the question.
SELECT z.Cat_tickets,
COALESCE(x.total_sold,0) total_sold,
COALESCE(y.total_scan,0) total_scan
FROM tickets z
LEFT JOIN
(
SELECT a.id_tickets,
a.cat_tickets,
SUM(b.sold_finance) total_sold
FROM tickets a
INNER JOIN finance b
ON a.id_tickets = b.id_tickets
WHERE id_event = 235
GROUP BY a.id_tickets, a.cat_tickets
) x ON z.id_tickets = x.id_tickets
LEFT JOIN
(
SELECT aa.id_tickets,
aa.cat_tickets,
SUM(bb.scan_access) total_scan
FROM tickets aa
INNER JOIN Access bb
ON aa.id_tickets = bb.id_tickets
WHERE id_event = 235
GROUP BY aa.id_tickets, aa.cat_tickets
) y ON z.id_tickets = y.id_tickets