am I doing this SQL code right? The query works, but it takes really long, 161 seconds (with LIMIT 2 set). Is there a way to optimize that?
SELECT p.itemid as `id`,
p.title as `name`,
pb.data_txt as `birthdate`,
pc.data_txt as `growth`,
pd.data_txt as `eyes`,
pe.data_txt as `desc`,
pf.data_txt as `weight`,
pg.data_txt as `sex`,
ph.data_txt as `hair`,
pi.data_txt as `dimensions`,
pj.data_txt as `lang`,
pk.data_txt as `school`,
pl.data_txt as `know`,
p.image as `image`
FROM `jos_sobi2_item` p
INNER JOIN `jos_sobi2_fields_data` AS pb ON pb.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pc ON pc.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pd ON pd.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pe ON pe.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pf ON pf.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pg ON pg.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS ph ON ph.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pi ON pi.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pj ON pj.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pk ON pk.itemid = p.itemid
INNER JOIN `jos_sobi2_fields_data` AS pl ON pl.itemid = p.itemid
WHERE
pb.fieldid = 16 AND
pc.fieldid = 17 AND
pd.fieldid = 21 AND
pe.fieldid = 13 AND
pf.fieldid = 18 AND
pg.fieldid = 19 AND
ph.fieldid = 20 AND
pi.fieldid = 22 AND
pj.fieldid = 25 AND
pk.fieldid = 23 AND
pl.fieldid = 24
LIMIT 2
I think part of the INNER JOIN is bad.
Try using conditional aggregation instead:
SELECT p.itemid as `id`, p.title as `name`,
max(case when fd.fieldid = 16 then data_txt end) as birthdate,
max(case when fd.fieldid = 17 then data_txt end) as growth,
. . .
FROM `jos_sobi2_item` p INNER JOIN
`jos_sobi2_fields_data` fd
ON fd.itemid = p.itemid
GROUP BY p.itemId, p.title;
You can add as many fields as you like, and adding more fields will have little impact on performance.
If you really want this even faster, you can do the limit on the first table:
SELECT p.itemid as `id`, p.title as `name`,
max(case when fd.fieldid = 16 then data_txt end) as birthdate,
max(case when fd.fieldid = 17 then data_txt end) as growth,
. . .
FROM (select p.*
from `jos_sobi2_item` p
limit 2
) p INNER JOIN
`jos_sobi2_fields_data` fd
ON fd.itemid = p.itemid
GROUP BY p.itemId, p.title;
Related
I building a custom SQL query of a product name with id_product, id_lang, id_manufacturer, category, meta_description, brand name and multiple feature ids. This SQL query shows no result.
Here's my query:
SELECT pl.id_product, pl.id_lang, ml.id_manufacturer, p.active, pl.name as name_product, fp.id_feature as name_attribute, cl.name as category, m.name as brand, pl.meta_description
FROM pr_product p
LEFT JOIN pr_product_lang pl ON (p.id_product = pl.id_product)
LEFT JOIN pr_category_lang cl ON (cl.id_category = p.id_category_default and cl.id_lang = pl.id_lang)
LEFT JOIN pr_lang l on (l.id_lang = pl.id_lang)
LEFT JOIN pr_manufacturer_lang ml on (l.id_lang = pl.id_lang and l.id_lang = ml.id_lang)
LEFT JOIN pr_manufacturer m on (ml.id_manufacturer = m.id_manufacturer)
LEFT JOIN pr_feature_product fp on (pl.id_product = fp.id_product)
Where l.active = 1 AND pl.id_lang = 2 AND cl.name = 9 and fp.id_feature = 2 AND fp.id_feature = 3 AND fp.id_feature = 35 AND fp.id_feature = 39
Order by p.id_product, pl.id_lang, ml.id_manufacturer, fp.id_feature
The goal is to creat a new meta description in the spreadsheet and import it to the database. In php, the query would be easier, but I have zero knowledge about it.
How to sum this query in single column.
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_hrc ih
ON hr.id = ih.human_resource_id
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 2018
AND ia.status_id = 0;
SELECT SUM(IFNULL(ih.amount,0.00)) amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_thrc ih
ON hr.id = ih.human_resource_id
AND ih.mca_id = 2
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 208
AND ia.status_id = 0;
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) distributed_amount
FROM revenue_and_expenses re
LEFT
JOIN mca_to_ee ie
ON re.id = ie.revenue_expenses_id
WHERE re.transaction_type = 2
AND ie.amount > 0
AND re.year = 2018
AND re.structure_id = 3
Wrap all three queries and SUM the alias amount.
Changed distributed_amount to amount
Amended year typo 208 to 2018
SELECT SUM(a.amount) FROM (
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_hrc ih ON(hr.id=ih.human_resource_id)
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id='0'
UNION ALL
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_thrc ih ON(hr.id=ih.human_resource_id AND ih.mca_id='2')
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id=0
UNION ALL
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) AS amount
FROM revenue_and_expenses re
LEFT JOIN mca_to_ee ie ON(re.id=ie.revenue_expenses_id)
WHERE re.transaction_type=2
AND ie.amount>0
AND re.year='2018'
AND re.structure_id='3') a
I'm helping a friend with an e-commerce site. He has options for users to select different colours, styles, use and type of the products he's selling. The query the adds the following to the query:
INNER JOIN tbl_coloursProducts col ON ( p.product_id = col.productID AND (col.colourID = 2 OR col.colourID = 3 OR col.colourID = 5 OR col.colourID = 8 OR col.colourID = 10))
INNER JOIN tbl_useProducts tbluse ON ( p.product_id = tbluse.productID AND (tbluse.useID = 15 OR tbluse.useID = 16 OR tbluse.useID = 17 OR tbluse.useID = 18))
INNER JOIN tbl_styleProducts style ON ( p.product_id = style.productID AND (style.styleID = 39 OR style.styleID = 44))
INNER JOIN tbl_typeProducts type ON ( p.product_id = type.productID AND (type.typeID = 46 OR type.typeID = 48 OR type.typeID = 50))
The query loads fast enough when only a few options are selecting, but some users are selecting multiple or each which is causing the query to run in excess of 30 seconds and timing out.
Without altering the table structure is there a better way to optimise the query?
This is the full query:
SELECT *,
p.product_id,
Coalesce((SELECT p2sp.price
FROM ab_product_specials p2sp
WHERE p2sp.product_id = p.product_id
AND p2sp.customer_group_id = '1'
AND ( ( p2sp.date_start = '0000-00-00'
OR p2sp.date_start < Now() )
AND ( p2sp.date_end = '0000-00-00'
OR p2sp.date_end > Now() ) )
ORDER BY p2sp.priority ASC,
p2sp.price ASC
LIMIT 1), p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
(SELECT Avg(r.rating)
FROM ab_reviews r
WHERE p.product_id = r.product_id
GROUP BY r.product_id) AS rating,
(SELECT Count(rw.review_id)
FROM ab_reviews rw
WHERE p.product_id = rw.product_id
GROUP BY rw.product_id) AS review
FROM ab_products p
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
Without the custom bits the query runs fine.
Looking at that query, not sure the ORs are the problem themselves (although you could possibly make the code more compact by using and IN clause for each one). Rather I suspect that selecting more and more options results in more rows being returned. And this is causing problems with the sub queries in the SELECT clause.
Can you try the query with the sub queries removed from the SELECT clause and see the effect that has.
You can remove the sub queries quite easily.
SELECT *,
p.product_id,
Coalesce(sub1.price, p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
sub0.rating,
sub0.review
FROM ab_products p
INNER JOIN
(
SELECT r.product_id,
Avg(r.rating) AS rating,
Count(rw.review_id) AS review
FROM ab_reviews r
GROUP BY r.product_id
) sub0
ON p.product_id = sub0.product_id
LEFT OUTER JOIN
(
SELECT p2sp.product_id,
SUBSTRING_INDEX(GROUP_CONCAT(p2sp.price ORDER BY p2sp.priority ASC, p2sp.price ASC ), ',', 1) AS price
FROM ab_product_specials p2sp
WHERE p2sp.customer_group_id = '1'
AND ( p2sp.date_start = '0000-00-00' OR p2sp.date_start < NOW() )
AND ( p2sp.date_end = '0000-00-00' OR p2sp.date_end > NOW() )
GROUP BY p2sp.product_id
) sub1
ON p.product_id = sub1.product_id
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
As an aside, when you read from ab_product_specials you are checking for the date_start and date_end to be 0000-00-00 (ie, dates), but also comparing them with NOW() which returns a date / time field. Are those fields date or date / time fields?
My first though was to use IN to make the query eaier to read:
INNER JOIN tbl_coloursProducts col
ON p.product_id = col.productID AND col.colourID IN ( 2, 3, 5, 8, 10 )
Then I thought, I wonder if they are dynamically building SQL text to squirt into the database logic?! The optimizer is unlikely to do well at optimizing queries when they are constantly mutating in this way.
Consider a scratch table (pseudo code):
-- One time:
CREATE TABLE SratchColours ( colourID INT NOT NULL UNQIUE );
-- For each query:
DELETE FROM SratchColours;
INSERT INTO SratchColours VALUES ( 2 ), ( 3 ), ( 5 ), ( 8 ), ( 10 );
Now you dynamic list of values simply becomes just another join:
tbl_coloursProducts NATURAL JOIN SratchColours
(or you could use an inner join if you must!)
Now, having one base table for every concurrent user is probably not a great way to scale a system. Therefore, consider how to pass a bag of colourID values to the database logic (say, a stored proc), put them into a table (say, a temporary table), then join from there to your base tables.
I have a query which Union's two separate queries with the same fields / data types. The query is as follows:
SELECT BusinessUnitName, BuildingNumber, Description, Value_1,
LifeRemaining, Sum_Quant
FROM
(
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbFloor ON b.BuildingID = tbFloor.BuildingID INNER JOIN
tbRoom as r ON tbFloor.FloorID = r.FloorID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON r.RoomID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
UNION
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON b.BuildingID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
) AS x
ORDER BY BusinessUnitName, Description
The results of the individual select queries are as follows with the first two lines coming from query 1 and the second two lines coming from query 2:
TEST PROPERTY | 1/A | Electrical services | 515.82 | 0 | 3
TEST PROPERTY | 1/A | Electrical services | 125 | 1 | 2
TEST PROPERTY | 1/A | Electrical services | 381.6 | 0 | 8
TEST PROPERTY | 1/A | Electrical services | 80615.93 | 5 | 7
My question is how can I now amalgamate the results of the the two queries so that the first result from both queries perform a SUM as they both have the value 0 in column 5? This will result in 3 rows of result with rows 1 and 3 combined.
Thanks in advance
Use
Derived GROUP BY your_value
Try like below,
SELECT BusinessUnitName, BuildingNumber, Description,
LifeRemaining, SUM(Value_1) as Value, SUM(Sum_Quant) as Quant
FROM
(
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbFloor ON b.BuildingID = tbFloor.BuildingID INNER JOIN
tbRoom as r ON tbFloor.FloorID = r.FloorID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON r.RoomID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
UNION
SELECT bu.BusinessUnitName, b.BuildingNumber, ec.Description, SUM(cc.MonetaryValue) AS Value_1,
cc.LifeRemaining, SUM(a.Quantity) AS Sum_Quant
FROM tbBuildingLinkBusinessUnit as blb INNER JOIN
tbBusinessUnit as bu ON blb.BusinessUnitID = bu.BusinessUnitID INNER JOIN
tbBuilding as b ON blb.BuildingID = b.BuildingID INNER JOIN
tbConditionComponent as cc INNER JOIN
tbAsset as a ON cc.ParentID = a.AssetUID INNER JOIN
tbElement as e ON cc.ElementID = e.ElementID AND a.ElementID = e.ElementID INNER JOIN
tbElementCategory as ec ON e.ElementCategoryID = ec.ElementCategoryID ON b.BuildingID = a.LocationID
WHERE (cc.MonetaryValue > 0)
GROUP BY bu.BusinessUnitName, b.BuildingNumber, ec.Description, a.Status, cc.LifeRemaining
HAVING (a.Status = 0)
) Derived GROUP BY BusinessUnitName, BuildingNumber, Description,
LifeRemaining
ORDER BY BusinessUnitName, Description
For reference
https://social.msdn.microsoft.com/forums/sqlserver/en-US/cd32bf58-c581-404b-a384-e62cdda7a131/union-all-and-group-by-query
hope it helps...
Hi I'm having an issue with a query that was once working. My SQL skills aren't all that great, not sure what I'm missing. Or if this is the correct approach. Maybe use a temp table instead?
The basic gist is given a certain time frame, I need to calculate the highest aggregate of points over 5 classes.
trialScores - keeps scores/points,
trials, dog, people and member tables are just meta data
classId 5 requires a different date range
Here is my Query on MySQL
select
t.id,
d.id,
p.id,
p.firstname,
p.lastname,
d.id dogId,
d.dogName,
c.id,
c.class,
t.trialStartDate,
s.points,
if(c.id = 5, '2012-08-01', '2012-11-18') as startDate,
if(c.id = 5, '2013-07-31', '2013-12-31') as endDate,
SUM(ts.points) AS pointsAggregate
from trialScores ts
inner join trials t on t.id = ts.trialId
inner join dogs d on d.id = ts.dogId
inner join people p on p.id = ts.personId
inner join classes c on c.id = ts.classId
where t.deletedAt is null
and ts.deletedAt is null
and ts.memberAtTrial = 1
and d.omitFromTripleCrownDOY = 0
and t.associationId = 1
GROUP BY p.id, ts.dogId, ts.classId
having t.trialStartDate between startDate and endDate
order by ts.classId, pointsAggregate desc
Looks like this fixed it, too much in the select and not in Group by?:
select
d.dogName,
c.class,
p.firstName,
p.lastName,
SUM(ts.points) AS pointsAggregate
from trialScores ts
inner join trials t on t.id = ts.trialId
inner join dogs d on d.id = ts.dogId
inner join people p on p.id = ts.personId
inner join classes c on c.id = ts.classId
where t.deletedAt is null
and ts.deletedAt is null
and ts.memberAtTrial = 1
and d.omitFromTripleCrownDOY = 0
and t.associationId = 1
and t.trialStartDate between if(c.id = 5, '2012-08-01', '2012-11-18') and if(c.id = 5, '2013-07-31', '2013-12-31')
GROUP BY ts.dogId, ts.classId
order by ts.classId, pointsAggregate desc
Can you try below query and let if it's work or not ?
select
d.dogName,
c.class,
p.firstName,
p.lastName,
SUM(ts.points) AS pointsAggregate
from trialScores ts
inner join trials t on t.id = ts.trialId
inner join dogs d on d.id = ts.dogId
inner join people p on p.id = ts.personId
inner join classes c on c.id = ts.classId
where t.deletedAt is null
and ts.deletedAt is null
and ts.memberAtTrial = 1
and d.omitFromTripleCrownDOY = 0
and t.associationId = 1
and t.trialStartDate between if(c.id = 5, '2012-08-01', '2012-11-18') and if(c.id = 5, '2013-07-31', '2013-12-31')
GROUP BY ts.classId,p.firstName,p.lastName
order by ts.classId, pointsAggregate desc