Duplicate sum operation - mysql

The sum operation is called more than once in my query and so the result that appears in column B2_ESTOQUE becomes inconsistent, maybe the cause of this is the amount of records that return in select and left join operations. That is an assumption.
Is there an error in the query below? Is the left join operation being used incorrectly?
SELECT
SB1.B1_FILIAL, SB1.B1_COD, SB1.B1_DESC, SB1.B1_TIPO, SB1.B1_UM, SB1.B1_SEGUM, SB1.B1_GRUPO, SB1.B1_CONV, SB1.B1_TIPCONV, SB1.B1_PRV1,
SB1.B1_PESO, SB1.B1_CODBAR, SB1.B1_QE, SB1.B1_MSBLQL, SB1.D_E_L_E_T_, SB1.R_E_C_N_O_, SB1.MD5, SB1.DATA_UPDATE,
(SELECT BM_DESC FROM PADRAO.PORTAL_SBM001 WHERE BM_GRUPO = SB1.B1_GRUPO LIMIT 0,1) as B1_GRUPO_DESCRICAO,
(SUM(IFNULL(SB2.B2_QATU, 0)) - SUM(IFNULL(SB2.B2_RESERVA, 0)) - SUM(IFNULL(SB2.B2_QPEDVEN, 0))) - SUM(IFNULL(SC6.C6_QTDVEN, 0)) AS B2_ESTOQUE
FROM PADRAO.PORTAL_SB1001 SB1
LEFT JOIN PADRAO.PORTAL_SB2001 SB2
ON SB1.B1_COD = SB2.B2_COD
LEFT JOIN PADRAO.PORTAL_SC6001_NEW SC6
ON SB1.B1_COD = SC6.C6_PRODUTO
AND (SC6.C6_NUM IS NULL OR SC6.C6_NUM = '')
AND SB2.B2_LOCAL IN ('07','08')
WHERE (SB1.D_E_L_E_T_ IS NULL OR SB1.D_E_L_E_T_ = '')
AND (SB2.D_E_L_E_T_ IS NULL OR SB2.D_E_L_E_T_ = '')
AND (SC6.D_E_L_E_T_ IS NULL OR SC6.D_E_L_E_T_ = '')
AND (SB1.B1_MSBLQL IS NULL OR SB1.B1_MSBLQL <> '1')
GROUP BY SB1.B1_COD;

I wasn't sure what all the checks for isnull and '' were about in the where clauses. I used coalesce to change null's to empty string and eliminated the values in the subqueries where clause instead of in the outermost where clause; but perhaps you wanted to keep the left joins Nulls which is why you checked for emptying string and null...
Nevertheless here's what I have as a UNTESTED query. Notice I converted the two left joined tables to sum the values before the join and group by the joined keys.
SELECT
SB1.B1_FILIAL
, SB1.B1_COD
, SB1.B1_DESC
, SB1.B1_TIPO
, SB1.B1_UM
, SB1.B1_SEGUM
, SB1.B1_GRUPO
, SB1.B1_CONV
, SB1.B1_TIPCONV
, SB1.B1_PRV1
, SB1.B1_PESO
, SB1.B1_CODBAR
, SB1.B1_QE
, SB1.B1_MSBLQL
, SB1.D_E_L_E_T_
, SB1.R_E_C_N_O_
, SB1.MD5
, SB1.DATA_UPDATE
,(SELECT BM_DESC FROM PADRAO.PORTAL_SBM001 WHERE BM_GRUPO = SB1.B1_GRUPO LIMIT 0,1) as B1_GRUPO_DESCRICAO
, SB2.mSum - SB6.mSUM as B2_ESTOQUE
FROM PADRAO.PORTAL_SB1001 SB1
LEFT JOIN (SELECT SB2.B2_COD, SUM(IFNULL(B2_QATU, 0) - IFNULL(B2_RESERVA, 0) - IFNULL(B2_QPEDVEN, 0)), AS mSum
FROM PADRAO.PORTAL_SB2001
WHERE B2_LOCAL IN ('07','08')
AND coalesce(SB2.D_E_L_E_T_,'')=''
GROUP BY SB2.B2_COD) SB2
ON SB1.B1_COD = SB2.B2_COD
LEFT JOIN (SELECT SUM(IFNULL(SC6.C6_QTDVEN, 0)) mSUM, C6_PRODUTO
FROM PADRAO.PORTAL_SC6001_NEW SC6
WHERE coalesce(SC6.C6_NUM,'') = ''
AND coalesce(SC6.D_E_L_E_T_,'') = ''
GROUP BY C6_PRODUTO)
ON SB1.B1_COD = SC6.C6_PRODUTO
WHERE (SB1.D_E_L_E_T_ IS NULL OR SB1.D_E_L_E_T_ = '')
AND (SB1.B1_MSBLQL IS NULL OR SB1.B1_MSBLQL <> '1')
GROUP BY SB1.B1_COD;

Related

MySQL with multiple SELECT and GROUP BY

I have a problem with my database in mysql. I would like to have a table from my database with date, pat, dureeP, dureeC but this function doesn't GROUP BY :
select *
from (SELECT date_format(p.date, "%Y-%m") AS date
,p.pat
,AVG(a) AS dureeP
FROM timing as t, patient as p
WHERE t.id_p = p.id_p
AND t.pos=6
AND t.heure_fin IS NOT NULL
GROUP BY p.pat, MONTH(p.date), YEAR(p.datede)
) as T1,
(SELECT AVG(b) AS dureeC
FROM timing as t, patient as p
WHERE t.id_p = p.id_p
AND t.pos=3
AND t.heure_fin IS NOT NULL
GROUP BY p.pathologie, MONTH(p.date), YEAR(p.date)
) as T2
With one SELECT I can have what I want but with multiple SELECT I can Group By.
Do you have an idea?
Thank you
To simplify your query you might be able to use "conditional aggregates" which basically means placing a case expression inside an aggregate function
SELECT
p.pathologie
, MONTH(p.date)
, YEAR(p.date)
, AVG(CASE WHEN t.pos = 3 THEN b END) AS dureeC
, AVG(CASE WHEN t.pos = 6 THEN a END) AS dureeP
FROM timing AS t
INNER JOIN patient AS p ON t.id_p = p.id_p
WHERE t.heure_fin IS NOT NULL
GROUP BY
p.pathologie
, MONTH(p.date)
, YEAR(p.date)

MySQL Query Help: Giving Two Different Results

My Sample Data: http://sqlfiddle.com/#!9/e29e54/7
My goal is to find a COUNT and SUM of sold items as well as quoted items.
SELECT
clients.`id`,
COUNT(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_count,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_client,
COUNT(clients.`id`) AS quote_count,
SUM(clients.`premium`) AS quote_client,
users.last_name, users.first_name
FROM `clients`
LEFT JOIN `users` ON `clients`.`user_id` = `users`.`id`
WHERE clients.`policy_date` IN (
SELECT policy_date FROM clients WHERE month(`policy_date`) = '2' AND year(`policy_date`) = '2018'
)
GROUP BY `users`.`last_name`
ORDER BY users.`id` ASC;
Both sold_count and quote_count return the same number, 3, as if "clients.paid_to_date != clients.policy_date" is not working. It should return 2 results for user_id = 1, John Smith.
This query returns 1 results for user:
SELECT id, client_number, policy_number, agent_name, paid_to_date, policy_date
FROM `clients` WHERE `user_id` = '1' AND month(`policy_date`) = '2'
AND year(`policy_date`) = '2018'
AND `paid_to_date` != `policy_date`
ORDER BY `policy_date` ASC
Any advise on how to get the sold_count and sold_clients IF statement to work correctly would be greatly appreciated!!
I would of thought for the first query
Sold Count = 2, instead of 3.
The sold_client is correctly adding the 2 results but the count is not correct.
Basher
So simple.. what was I thinking. here's my solution:
SELECT clients.id,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, 1, 0)) AS sold_count,
SUM(IF(clients.`paid_to_date` != clients.`policy_date`, `premium`, 0)) AS sold_client,
COUNT(clients.`id`) AS quote_count,
SUM(clients.`premium`) AS quote_client, users.last_name, users.first_name
FROM `clients`
LEFT JOIN `users` ON `clients`.`user_id` = `users`.`id`
WHERE clients.`policy_date` IN (
SELECT policy_date FROM clients WHERE month(`policy_date`) = '2' AND year(`policy_date`) = '2018'
)
GROUP BY users.`last_name`
ORDER BY users.`id` ASC;
Changed first SUM() to just sum the result count.

Order by clause not behaving correctly after several joins

Here is my query:
SELECT DISTINCT `post_data`. * , pv.`seller_id` , pv.`islimited` , pv.`isquantity` , pv.`isslider`, `price`.`original_price` , `price`.`discount_percentage` , `timelimit`.`start_date` , `timelimit`.`expire_date` , `quantity`.`in_stock`, `currency`.`currency_symbol`, `seller`.`directory`, `post_to_cat`.`cat_id`, count(`sales`.`sales_id`) as sale FROM `post_view` AS pv
INNER JOIN `post_data` ON pv.`post_id` = `post_data`.`post_id` AND pv.`status` = 1
INNER JOIN `price` ON pv.`post_id` = `price`.`post_id`
INNER JOIN `currency` ON `price`.`currency_id` = `currency`.`currency_id`
INNER JOIN `seller` ON pv.`seller_id` = `seller`.`seller_id`
INNER JOIN `post_to_cat` ON `post_to_cat`.`cat_id` = 1 AND `post_to_cat`.`post_id` = `post_data`.`post_id`
LEFT JOIN `timelimit` ON ( CASE WHEN pv.`islimited` = 1 THEN `timelimit`.`post_id` ELSE -1 END ) = pv.`post_id`
LEFT JOIN `quantity` ON ( CASE WHEN pv.`isquantity` = 1 THEN `quantity`.`post_id` ELSE -1 END ) = pv.`post_id`
LEFT JOIN `sales` ON `sales`.`post_id` = pv.`post_id` AND `sales`.`status` = 1
WHERE pv.`status` = 1
ORDER BY pv.`post_id` DESC LIMIT 1
The ORDER BY DESC is not working, it just returns the first row from the table, but I want to get the highest post_id value row. What is the mistake I am making?
AS #Alex said in the comments you've got a LIMIT 1 at the end, you should probably bracket the last LEFT JOIN also for readability.
As #McAdam331 said we need data sample and sql fiddle to investigate what is wrong with you query. But at the moment I have some suggestions how to improve and debug your query.
First off all, what do I see the main and very left table in your query is post_view so all other tables should be LEFT JOIN if you want to get the max id. You should use INNER JOIN only if you think that other table could filter your main table somehow and order or result could be other table dependend. But in your case I see no reason to use INNER JOIN.
Second point is your very weird ON conditions:
LEFT JOIN `timelimit` ON ( CASE WHEN pv.`islimited` = 1 THEN `timelimit`.`post_id` ELSE -1 END ) = pv.`post_id`
LEFT JOIN `quantity` ON ( CASE WHEN pv.`isquantity` = 1 THEN `quantity`.`post_id` ELSE -1 END ) = pv.`post_id`
I have converted them into another one
CASE WHEN pv.`islimited`=1 THEN `timelimit`.`start_date` ELSE NULL END as start_date ,
CASE WHEN pv.`islimited`=1 THEN `timelimit`.`expire_date` ELSE NULL END as expire_date,
CASE WHEN pv.`isquantity`=1 THEN `quantity`.`in_stock` ELSE NULL END as in_stock,
But I still don't like it. It seems very useless to me. And has no sense when I read CASE WHEN pv.islimited=1 THEN timelimit.start_date ELSE NULL END as start_date so if flag pv.islimited=0 you don't need start_date? Are you sure?
And the last thing I can suggest: try to use my or even your query. But add every table by step while debugging. So First query just:
SELECT
pv.`post_id`, pv.`seller_id` , pv.`islimited` , pv.`isquantity` ,
pv.`isslider`
FROM `post_view` AS pv
WHERE pv.`status` = 1
ORDER BY pv.`post_id` DESC
LIMIT 1
If it returns correct post_id add next table:
SELECT
pv.`post_id`, pv.`seller_id` , pv.`islimited` , pv.`isquantity` ,
pv.`isslider`,
`post_data`. *
FROM `post_view` AS pv
LEFT JOIN `post_data`
ON pv.`post_id` = `post_data`.`post_id`
WHERE pv.`status` = 1
AND `post_data`.`slug` = 'abc'
ORDER BY pv.`post_id` DESC
LIMIT 1
Check the result. And continue step by step.
Yes it takes time. But that is debugging process. It could be the fastest way to get that query done. :-)
SELECT `post_data`. * ,
pv.`post_id`, pv.`seller_id` , pv.`islimited` , pv.`isquantity` ,
pv.`isslider`, `price`.`original_price` , `price`.`discount_percentage` ,
CASE WHEN pv.`islimited`=1 THEN `timelimit`.`start_date` ELSE NULL END as start_date ,
CASE WHEN pv.`islimited`=1 THEN `timelimit`.`expire_date` ELSE NULL END as expire_date,
CASE WHEN pv.`isquantity`=1 THEN `quantity`.`in_stock` ELSE NULL END as in_stock,
`currency`.`currency_symbol`, `seller`.`directory`, `post_to_cat`.`cat_id`, count(`sales`.`sales_id`) as sale
FROM `post_view` AS pv
LEFT JOIN `post_data`
ON pv.`post_id` = `post_data`.`post_id`
LEFT JOIN `price`
ON pv.`post_id` = `price`.`post_id`
LEFT JOIN `currency`
ON `price`.`currency_id` = `currency`.`currency_id`
LEFT JOIN `seller`
ON pv.`seller_id` = `seller`.`seller_id`
LEFT JOIN `post_to_cat`
ON `post_to_cat`.`cat_id` = 1
AND `post_to_cat`.`post_id` = pv.`post_id`
LEFT JOIN `timelimit`
ON `timelimit`.`post_id` = pv.`post_id`
LEFT JOIN `quantity`
ON quantity`.`post_id` = pv.`post_id`
LEFT JOIN `sales`
ON `sales`.`post_id` = pv.`post_id`
AND `sales`.`status` = 1
WHERE pv.`status` = 1
AND `post_data`.`slug` = 'abc'
GROUP BY pv.`post_id`
ORDER BY pv.`post_id` DESC
LIMIT 1
EDIT 1 - last GROUP BY pv.post_id was added as per #McAdam331 notice about count() function without GROUP BY
I believe the issue here is mostly as a result of preforming aggregation (using the COUNT()) function, without any group by. Although, it seems like you don't necessarily need it because you want that count only for the post in question.
If you're trying to gather all of that information for a single post, I would adjust your WHERE clause to have a condition to only gather that information for the post with the largest ID.
Instead of ordering by ID and limiting by 1, use a subquery to get the largest id, like this:
...
WHERE pv.status = 1 AND post_data.slug = 'abc' AND pv.post_id = (SELECT MAX(post_id) FROM post_view);

MySQL: How to optimize this query?

I almost spent a day to optimize this query:
SELECT
prod. *,
cat.slug category_slug,
sup.bname bname,
sup.slug bname_slug
FROM bb_admin.bb_directory_products AS prod
LEFT JOIN bb_admin.bb_categories_products AS cat
ON prod.primary_category_id = cat.category_id
LEFT JOIN bb_admin.bb_directory_suppliers AS sup
ON prod.supplier_id = sup.supplier_id
LEFT JOIN bb_admin.bb_directory_suppliers AS credit_sup
ON prod.credit_supplier_id = credit_sup.supplier_id
LEFT JOIN bb_admin.bb_directory_suppliers AS photo_sup
ON prod.photo_supplier_id = photo_sup.supplier_id
WHERE (
prod.status = '1'
OR prod.status = '3'
OR prod.status = '5'
)
AND (
sup.active_package_id != '1'
OR sup.active_package_id != '5'
OR sup.active_package_id != '6'
OR prod.supplier_id = '0'
)
AND (
sup.supplier_id = '1989'
OR credit_sup.supplier_id = '1989'
OR photo_sup.supplier_id = '1989'
)
GROUP BY prod.product_id
ORDER BY prod.priority_index ASC
Can you help me to optimized this query?
Update your column data types to be INT or one of its variants, since the ones you are checking against are all integer IDs (assumption).
Create indexes on following columns(if possible in all tables):
prod.status
supplier_id
active_package_id
Use IN clause instead of concatenating OR segments.
I'll be putting the updated WHERE clause here:
WHERE prod.status IN(1, 3, 5)
AND ( sup.active_package_id NOT IN(1, 5, 6)
OR prod.supplier_id = 0
)
AND 1989 IN (prod.supplier_id, prod.credit_supplier_id, prod.photo_supplier_id)

Left Joins returns duplicate values

The result I receive:
id sku name GROUP_CONCAT(quantity_received) GROUP_CONCAT(item_cost)
4 00004 Antibacterial Wipes 50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309,50,14,25,309 3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49,3.29,3.29,3.29,3.49
The result I want:
id sku name GROUP_CONCAT(DISTINCT quantity_received) GROUP_CONCAT(DISTINCT item_cost)
4 00004 Antibacterial Wipes 50,14,25,309 3.29,3.49
The way I resolved this issue was placing DISTINCT in the quantity_recieved select. The problem is that if the quantity has two values that are the same such as 50, 50, 14, 25. The result will be 50, 14, 25. I just want to get rid of the repeating numbers and only get the values once.
Here is the query:
SELECT `product`.`id`,`product`.`sku`,`product`.`name`,
case when coalesce(stock1.`quantity`, '') = ''
then '0'
else stock1.`quantity`
end as qty_warehouse,
case when coalesce(sum(distinct stock2.`quantity`), '') = ''
then '0'
else sum(distinct stock2.`quantity`)
end as qty_events,
case when coalesce(stock1.`quantity`, '') = ''
then '0'
else stock1.`quantity`
end +
case when coalesce(sum(distinct stock2.`quantity`), '') = ''
then '0'
else sum(distinct stock2.`quantity`)
end as qty_total
GROUP_CONCAT(DISTINCT quantity_received) ,
GROUP_CONCAT(DISTINCT item_cost)
FROM (`product`)
LEFT JOIN`shipping_event`
ON `shipping_event`.`product_id` = `product`.`id`
LEFT JOIN `product_stock` as stock1
ON `product`.`id` = `stock1`.`product_id` and `stock1`.`location_id` = 112
LEFT JOIN `product_stock` as stock2
ON `product`.`id` = `stock2`.`product_id` and `stock2`.`location_id` != 112
LEFT JOIN `shipping_list`
ON `shipping_event`.`shipping_list_id` = `shipping_list`.`id`
WHERE `shipping_list`.`type` = 'incoming'
AND `shipping_event`.`end_date` > '2004-01-01 01:01:01'
GROUP BY `product`.`id`
ORDER BY `sku` asc LIMIT 20
I am using group concat just to display the result in this case. I actually sum the quantity_received and then multiple them by the item cost.
You could make a subquery with a GROUP BY and then JOIN to the product table.
The same logic can be applied to the other joined tables as well. If you do that, you can skip the GROUP BY product.id:
SELECT p.id
, p.sku
, p.name
, COALESCE(stock1.quantity, 0) --- minor improvements on
AS qty_warehouse --- the long CASE clauses
, COALESCE(SUM(DISTINCT stock2.quantity), 0)
AS qty_events
, COALESCE(stock1.quantity, 0) + COALESCE(SUM(DISTINCT stock2.quantity), 0)
AS qty_total
, grp.all_quantities_received
, grp.all_item_costs
FROM product AS p
LEFT JOIN
( SELECT product_id
, GROUP_CONCAT(se.quantity_received) AS all_quantities_received
, GROUP_CONCAT(se.item_cost) AS all_item_costs
FROM shipping_event AS se
LEFT JOIN shipping_list AS sl
ON se.shipping_list_id = sl.id
WHERE sl.type = 'incoming'
AND se.end_date > '2004-01-01 01:01:01'
GROUP BY se.product_id
) AS grp
ON grp.product_id = p.id
LEFT JOIN `product_stock` AS stock1
ON p.id = stock1.product_id
AND stock1.location_id = 112
LEFT JOIN product_stock AS stock2
ON p.id = stock2.product_id
AND stock2.location_id <> 112
GROUP BY p.id
ORDER BY sku ASC
LIMIT 20