The view below does not return correct results. I am trying to get the sum of Picked, Printed & Scanned grouped by Plan_Id & PartNum. I need to return the correct totals regardless if there are corresponding records in the child tables. I know how to do it if I use three different views and join them, but how do i do it all in a single view? Any help appreciated.
SELECT
`prod_plan`.`Prp_ProdPlanId` AS `PlanId`,
`prod_plan`.`Prp_PartNum` AS `PartNum`,
sum(`prod_plan`.`Prp_Picked`) AS `Picked`,
sum(`printed`.`PtQty`) AS `Printed`,
sum(`scanned`.`PtQty`) AS `Scanned`
FROM
(
(
`prod_plan`
LEFT JOIN `product_trans` `printed` ON (
(
(
`printed`.`PtPlanId` = `prod_plan`.`Prp_ProdPlanId`
)
AND (
`printed`.`PtPartNum` = `prod_plan`.`Prp_PartNum`
)
)
)
)
LEFT JOIN `product_trans` `scanned` ON (
(
(
`scanned`.`PtPlanId` = `prod_plan`.`Prp_ProdPlanId`
)
AND (
`scanned`.`PtPartNum` = `prod_plan`.`Prp_PartNum`
)
)
)
)
WHERE
(
(
`printed`.`PtPart` = 'Barcode Print'
)
AND (
`scanned`.`PtPart` = 'Barcode Scan'
)
)
GROUP BY
`prod_plan`.`Prp_ProdPlanId`,
`prod_plan`.`Prp_PartNum`
You need to check PtPart in the ON clauses. Otherwise, you won't get the rows with no matches in the child tables, because those columns will be NULL.
SELECT
`prod_plan`.`Prp_ProdPlanId` AS `PlanId`,
`prod_plan`.`Prp_PartNum` AS `PartNum`,
sum(`prod_plan`.`Prp_Picked`) AS `Picked`,
sum(`printed`.`PtQty`) AS `Printed`,
sum(`scanned`.`PtQty`) AS `Scanned`
FROM `prod_plan`
LEFT JOIN `product_trans` `printed`
ON `printed`.`PtPlanId` = `prod_plan`.`Prp_ProdPlanId`
AND `printed`.`PtPartNum` = `prod_plan`.`Prp_PartNum`
AND `printed`.`PtPart` = 'Barcode Print'
LEFT JOIN `product_trans` `scanned`
ON `scanned`.`PtPlanId` = `prod_plan`.`Prp_ProdPlanId`
AND `scanned`.`PtPartNum` = `prod_plan`.`Prp_PartNum`
AND `scanned`.`PtPart` = 'Barcode Scan'
GROUP BY
`prod_plan`.`Prp_ProdPlanId`,
`prod_plan`.`Prp_PartNum`
Here is what I have done. Below are 3 views that work correctly.
v_trans_printed:
SELECT
product_trans.PtPlanId AS PlanId,
product_trans.PtLot AS Lot,
product_trans.PtPartNum AS PartNum,
Sum(product_trans.PtQty) AS Printed
FROM
product_trans
WHERE
product_trans.PtPart = 'Barcode Print'
GROUP BY
product_trans.PtPlanId,
product_trans.PtLot,
product_trans.PtPartNum
v_trans_scanned:
SELECT
product_trans.PtPlanId AS PlanId,
product_trans.PtLot AS Lot,
product_trans.PtPartNum AS PartNum,
Sum(product_trans.PtQty) AS Scanned
FROM
product_trans
WHERE
product_trans.PtPart = 'Barcode Scan'
GROUP BY
product_trans.PtPlanId,
product_trans.PtLot,
product_trans.PtPartNum
And here I put them all together. This returns the correct results:
vSELECT
prod_plan.Prp_ProdPlanId AS PlanId,
prod_plan.Prp_Lot AS Lot,
prod_plan.Prp_PartNum AS PartNum,
Sum(prod_plan.Prp_Picked) AS Picked,
Printed.Printed AS Printed,
Scanned.Scanned AS Scanned
FROM
prod_plan
LEFT JOIN v_trans_printed AS Printed ON Printed.PlanId = prod_plan.Prp_ProdPlanId AND Printed.Lot = prod_plan.Prp_Lot AND Printed.PartNum = prod_plan.Prp_PartNum
LEFT JOIN v_trans_scanned AS Scanned ON Scanned.PlanId = prod_plan.Prp_ProdPlanId AND Scanned.Lot = prod_plan.Prp_Lot AND Scanned.PartNum = prod_plan.Prp_PartNum
GROUP BY
prod_plan.Prp_ProdPlanId,
prod_plan.Prp_Lot,
prod_plan.Prp_PartNum
But it would be better if I could use one view.
Note: I left out Lot originally by accident. But it didn't affect the results w. the sample data set.
Related
I have latest dates of 2017 in attandance date but its show just 2016 dates kindly plz help me
SELECT
added_on,
types. `type`,
student.`student_id`, student.`roll`, student.`class_id`, student.`name` AS student_name,
SUM(datewise_attandance.`total_classes`) AS SumOfTotal,
datewise_attandance.attandance_date AS attandance_date,
SUM(datewise_attandance.`status`) AS SumOfPresent,
#ROUND(((SUM(datewise_attandance.`status`)/SUM(datewise_attandance.`total_classes`))*100),2) AS percentage,
class.`name` AS class_name, student.`sex`, student.`father_name`, student.`address`,
student.`phone`, subject.`name` AS subject_name,
#types.`type`, types.`type_id`,
subject.`subject_id`,
#MAX( datewise_attandance.`date_to` ) AS MaxOfAtt_Date_To,
student.`session_id`
FROM
(( class
INNER JOIN `subject` ON class.`class_id` = subject.`class_id` )
INNER JOIN datewise_attandance # ( INNER JOIN types ON datewise_attandance.`type_id` = types.`type_id` )
ON ( subject.`subject_id` = datewise_attandance.`subject_id` )
AND ( class.`class_id` = datewise_attandance.`class_id` ))
INNER JOIN `types` ON( types.`type_id` = subject.`subject_type`)
INNER JOIN student ON ( student.`student_id` = datewise_attandance.`std_id` )
AND ( class.`class_id` = student.`class_id` )
GROUP BY student.`student_id`,
student.`roll`, student.`class_id`, student.`name`, class.`name`,
student.`sex`, student.`father_name`, student.`address`,
student.`phone`, subject.`name`,
# types.`type`, types.`type_id`,
subject.`subject_id`, student.`session_id`
HAVING (
(
student.`class_id` = 4
AND student.`roll` = 388
AND student.`session_id` = 5
)
) ORDER BY IFNULL(subject.final_exam,0) DESC
You are using inner join so if there are matching records then only result will be returned for 2017. Why dont you use left join and try the same
I have this below:
SELECT a.* FROM ( SELECT
asset_liability_income_expenditure_tbl.a_l_code,
SUM(mainaccount_a_2017.amount), mainaccount_a_2017.dr_cr_action
FROM `mainaccount_a_2017` LEFT JOIN chart_of_account
ON (
chart_of_account.joint_account_numbers =
mainaccount_a_2017.joint_account_number
)
LEFT JOIN asset_liability_income_expenditure_tbl
ON (
asset_liability_income_expenditure_tbl.a_l_code =
chart_of_account.account_type
)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_a_2017.dr_cr_action = 'DR' UNION
SELECT asset_liability_income_expenditure_tbl.a_l_code,
SUM(mainaccount_b_2017.amount),
mainaccount_b_2017.dr_cr_action
FROM `mainaccount_b_2017`
LEFT JOIN chart_of_account ON (
chart_of_account.joint_account_numbers =
mainaccount_b_2017.joint_account_number
)
LEFT JOIN asset_liability_income_expenditure_tbl ON (
asset_liability_income_expenditure_tbl.a_l_code =
chart_of_account.account_type
)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_b_2017.dr_cr_action = 'DR'
) AS a
it works fine, but displays either one empty row at the top and the sum below or vis-a-vis. I tried LIMIT 1, but the problem is when the SUM(amount) outputs in row 2, i cannot fetch and if I don't apply any limit, it only fetches result whose SUM(amount) outputs in row 1. I don't know what am missing. Please kindly assist. Thanks.
I figured it out. I had to flip something. Results below:
SELECT SUM(a) FROM
(
SELECT SUM(mainaccount_a_2017.amount)
AS a FROM `mainaccount_a_2017`
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_a_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA'
AND mainaccount_a_2017.dr_cr_action = 'DR'
UNION ALL
SELECT SUM(mainaccount_b_2017.amount)
AS a FROM `mainaccount_b_2017`
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_b_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE asset_liability_income_expenditure_tbl.a_l_code = 'FA' AND mainaccount_b_2017.dr_cr_action = 'DR'
) a
I have MySQL query currently selecting and joining 13 tables and finally grouping ~60k rows. The query without grouping takes ~0ms but with grouping the query time increases to ~1.7sec. The field, which is used for grouping is primary field and is indexed. Where could be the issue?
I know group by without aggregate is considered invalid query and bad practise but I need distinct base table rows and can not use DISTINCT syntax.
The query itself looks like this:
SELECT `table_a`.*
FROM `table_a`
LEFT JOIN `table_b`
ON `table_b`.`invoice` = `table_a`.`id`
LEFT JOIN `table_c` AS `r1`
ON `r1`.`invoice_1` = `table_a`.`id`
LEFT JOIN `table_c` AS `r2`
ON `r2`.`invoice_2` = `table_a`.`id`
LEFT JOIN `table_a` AS `i1`
ON `i1`.`id` = `r1`.`invoice_2`
LEFT JOIN `table_a` AS `i2`
ON `i2`.`id` = `r2`.`invoice_1`
JOIN `table_d` AS `_u0`
ON `_u0`.`id` = 1
LEFT JOIN `table_e` AS `_ug0`
ON `_ug0`.`user` = `_u0`.`id`
JOIN `table_f` AS `_p0`
ON ( `_p0`.`enabled` = 1
AND ( ( `_p0`.`role` < 2
AND `_p0`.`who` IS NULL )
OR ( `_p0`.`role` = 2
AND ( `_p0`.`who` = '0'
OR `_p0`.`who` = `_u0`.`id` ) )
OR ( `_p0`.`role` = 3
AND ( `_p0`.`who` = '0'
OR `_p0`.`who` = `_ug0`.`group` ) ) ) )
AND ( `_p0`.`action` = '*'
OR `_p0`.`action` = 'read' )
AND ( `_p0`.`related_table` = '*'
OR `_p0`.`related_table` = 'table_name' )
JOIN `table_a` AS `_e0`
ON ( ( `_p0`.`related_id` = 0
OR `_p0`.`related_id` = `_e0`.`id`
OR `_p0`.`related_user` = `_e0`.`user`
OR `_p0`.`related_group` = `_e0`.`group` )
OR ( `_p0`.`role` = 0
AND `_e0`.`user` = `_u0`.`id` )
OR ( `_p0`.`role` = 1
AND `_e0`.`group` = `_ug0`.`group` ) )
AND `_e0`.`id` = `table_a`.`id`
JOIN `table_d` AS `_u1`
ON `_u1`.`id` = 1
LEFT JOIN `table_e` AS `_ug1`
ON `_ug1`.`user` = `_u1`.`id`
JOIN `table_f` AS `_p1`
ON ( `_p1`.`enabled` = 1
AND ( ( `_p1`.`role` < 2
AND `_p1`.`who` IS NULL )
OR ( `_p1`.`role` = 2
AND ( `_p1`.`who` = '0'
OR `_p1`.`who` = `_u1`.`id` ) )
OR ( `_p1`.`role` = 3
AND ( `_p1`.`who` = '0'
OR `_p1`.`who` = `_ug1`.`group` ) ) ) )
AND ( `_p1`.`action` = '*'
OR `_p1`.`action` = 'read' )
AND ( `_p1`.`related_table` = '*'
OR `_p1`.`related_table` = 'table_name' )
JOIN `table_g` AS `_e1`
ON ( ( `_p1`.`related_id` = 0
OR `_p1`.`related_id` = `_e1`.`id`
OR `_p1`.`related_user` = `_e1`.`user`
OR `_p1`.`related_group` = `_e1`.`group` )
OR ( `_p1`.`role` = 0
AND `_e1`.`user` = `_u1`.`id` )
OR ( `_p1`.`role` = 1
AND `_e1`.`group` = `_ug1`.`group` ) )
AND `_e1`.`id` = `table_a`.`company`
WHERE `table_a`.`date_deleted` IS NULL
AND `table_a`.`company` = 4
AND `table_a`.`type` = 1
AND `table_a`.`date_composed` >= '2016-05-04 14:43:55'
GROUP BY `table_a`.`id`
The ORs kill performance.
This composite index may help: INDEX(company, type, date_deleted, date_composed).
LEFT JOIN table_b ON table_b.invoice = table_a.id seems to do absolutely nothing other than slow down the processing. No fields of table_b are used or SELECTed. Since it is a LEFT join, it does not limit the output. Etc. Get rid if it, or justify it.
Ditto for other joins.
What happens with JOIN and GROUP BY: First, all the joins are performed; this explodes the number of rows in the intermediate 'table'. Then the GROUP BY implodes the set of rows.
One technique for avoiding this explode-implode sluggishness is to do
SELECT ...,
( SELECT ... ) AS ...,
...
instead of a JOIN or LEFT JOIN. However, that works only if there is zero or one row in the subquery. Usually this is beneficial when an aggregate (such as SUM) can be moved into the subquery.
For further discussion, please include SHOW CREATE TABLE.
I am trying to bring back a string based on an IF statement but it is extremely slow.
It has something to do with the first subquery but I am unsure of how to rearrange this as to bring back the same results but faster.
Here is my SQL:
SELECT IF
(
(
SELECT COUNT(*)
FROM
(
SELECT DISTINCT enquiryId, type
FROM parts_enquiries, parts_service_types AS pst
WHERE parts_enquiries.serviceTypeId = pst.id
) AS parts
WHERE parts.enquiryId = enquiries.id
) > 1, 'Mixed',
(
SELECT DISTINCT type
FROM parts_enquiries, parts_service_types AS pst
WHERE parts_enquiries.serviceTypeId = pst.id AND enquiryId = enquiries.id
)
) AS partTypes
FROM enquiries,
entities
WHERE enquiries.entityId = entities.id
How can I make it faster?
I have modified my original query below, but I am getting the error that subquery returns more than one row:
SELECT
(SELECT
CASE WHEN COUNT(DISTINCT type) > 1 THEN 'Mixed' ELSE `type` END AS type
FROM parts_enquiries
INNER JOIN parts_service_types AS pst ON parts_enquiries.serviceTypeId = pst.id
INNER JOIN enquiries ON parts_enquiries.enquiryId = enquiries.id
INNER JOIN entities ON enquiries.entityId = entities.id
GROUP BY enquiryId) AS partTypes
FROM enquiries,
entities
WHERE enquiries.entityId = entities.id
Please have a look if this query yields the same results:
SELECT
enquiryId,
CASE WHEN COUNT(DISTINCT type) > 1 THEN 'Mixed' ELSE `type` END AS type
FROM parts_enquiries
INNER JOIN parts_service_types AS pst ON parts_enquiries.serviceTypeId = pst.id
INNER JOIN enquiries ON parts_enquiries.enquiryId = enquiries.id
INNER JOIN entities ON enquiries.entityId = entities.id
GROUP BY enquiryId
But N.B.'s comment is still valid. To see if and index is used and other information we need to see the EXPLAIN and the table definitions.
This should get you what you want.
I would first pre-query your parts enquiries and parts service types looking for both the count and MINIMUM of the part 'type', grouped by the enquiry ID.
then, run your IF() against that result. If the distinct count is > 0, then 'Mixed'. If only one, since I did the MIN(), it would only have the description of that one value that you desire anyhow.
SELECT
E.ID
IF ( PreQuery.DistTypes > 1, 'Mixed', PreQuery.FirstType ) as PartType
from
Enquiries E
JOIN ( SELECT
PE.EnquiryID,
COUNT( DISTINCT PE.ServiceTypeID ) as DistTypes,
MIN( PST.Type ) as FirstType
from
Parts_Enquiries PE
JOIN Parts_Service_Types PST
ON PE.ServiceTypeID = PST.ID
group by
PE.EnquiryID ) as PreQuery
ON E.ID = PreQuery.EnquiryID
I'm wanting to optimize a query using a union as a sub query. Im not really sure how to construct the query though. I'm using MYSQL 5
Here is the original query:
SELECT Parts.id
FROM Parts_Category, Parts
LEFT JOIN Image ON Parts.image_id = Image.id
WHERE
(
(
Parts_Category.category_id = '508' OR
Parts_Category.main_category_id ='508'
) AND
Parts.id = Parts_Category.Parts_id
) AND
Parts.status = 'A'
GROUP BY
Parts.id
What I want to do is replace this ( (Parts_Category.category_id = '508' OR Parts_Category.main_category_id ='508' ) part with the union below. This way I can drop the GROUP BY clause and use straight col indexes which should improve performance. Parts and parts category tables contains half a million records each so any gain would be great.
(
SELECT * FROM
(
(SELECT Parts_id FROM Parts_Category WHERE category_id = '508')
UNION
(SELECT Parts_id FROM Parts_Category WHERE main_category_id = '508')
)
as Parts_id
)
Can anybody give me a clue on how to re-write it? I've tried for hours but can't get it as I'm only fairly new to MySQL.
SELECT Parts.id
FROM (
SELECT parts_id
FROM Parts_Category
WHERE Parts_Category.category_id = '508'
UNION
SELECT parts_id
FROM Parts_Category
WHERE Parts_Category.main_category_id = '508'
) pc
JOIN Parts
ON parts.id = pc.parts_id
AND Parts.status = 'A'
LEFT JOIN
Image
ON image.id = parts.image_id
Note that MySQL can use Index Merge and you can rewrite your query as this:
SELECT Parts.id
FROM (
SELECT DISTINCT parts_id
FROM Parts_Category
WHERE Parts_Category.category_id = '508'
OR Parts_Category.main_category_id = '508'
) pc
JOIN Parts
ON parts.id = pc.parts_id
AND Parts.status = 'A'
LEFT JOIN
Image
ON image.id = parts.image_id
, which will be more efficient if you have the following indexes:
Parts_Category (category_id, parts_id)
Parts_Category (main_category_id, parts_id)