I need to write a query which involves subquery and do indexing. So, I came up with a query to find the team name which has the Highest build up speed in a year:
SELECT CONCAT(team_long_name, ',', team_short_name) AS TeamName,
EXTRACT(YEAR FROM date) AS Year,
buildUpPlaySpeed
FROM team JOIN
team_attributes
ON team.team_api_id = team_attributes.team_api_id
WHERE
(buildUpPlaySpeed,team_attributes.date) in (SELECT
MAX(buildUpPlaySpeed),team_attributes.date
FROM team_attributes
WHERE team_attributes.date = team_attributes.date
group by team_attributes.date)
ORDER BY date desc;
Indexes are present on date,team_api_id,buildUpPlaySpeed columns.
Any suggestions on how to reduce the cost further??
Yes. Replace the correlated subquery with a join:
SELECT CONCAT (
team_long_name
,','
,team_short_name
) AS TeamName
,EXTRACT(YEAR FROM [DATE]) AS Year
,buildUpPlaySpeed
FROM team
INNER JOIN team_attributes ON team.team_api_id = team_attributes.team_api_id
INNER JOIN (
SELECT MAX(buildUpPlaySpeed) maxbuildup
,team_attributes.[DATE]
FROM team_attributes
WHERE team_attributes.[DATE] = team_attributes.DATE
GROUP BY team_attributes.[DATE]
) x ON buildUpPlaySpeed = x.maxbuildup
AND team_attributes.DATE = x.[DATE]
ORDER BY [DATE] DESC
;
and, for sanity's sake please don't name columns "date" because that's used by SQL. Very confusing.
try this also
SELECT CONCAT(team_long_name,',',team_short_name) AS TeamName,EXTRACT(YEAR FROM DATE) AS Year,buildUpPlaySpeed
FROM team
INNER JOIN team_attributes ON team.team_api_id = team_attributes.team_api_id
INNER JOIN ( SELECT MAX(buildUpPlaySpeed) maxbuildup,team_attributes.DATE FROM team_attributes
WHERE team_attributes.DATE = team_attributes.DATE
GROUP BY team_attributes.DATE ) t1
where buildUpPlaySpeed = t1.maxbuildup AND team_attributes.DATE = t1.DATE ORDER BY DATE DESC;
Related
I have this query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProdServiceID=(SELECT ProdServiceID FROM
ProductServices WHERE ProductID=prod.ProductID ORDER BY Modified DESC LIMIT
1) ;
This query returns 175 rows
I want to convert this to JOIN.
I used below query:
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls1.ProductServicesID
FROM Products prod
inner join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductServicesID, ProductID, max(Modified) as Modified
FROM
ProductServices group by Modified) as ls1 ON ls.ProductServicesID =
ls1.ProductServicesID and ls.Modified = ls1.Modified and ls.ProductID =
ls1.ProductID;
which doesn't return correct result. Can I get some direction on this.
The purpose is to optimize the query. Would it be good idea to use join in place of original query.
Thanks!
Try this:
SELECT ProductID
, Name
, ProdExtID
, ProdServiceID
FROM
(
SELECT prod.ProductID
, prod.Name
, prod.ProdExtID
, ls.ProdServiceID
, RANK() OVER(PARTITION BY ls.ProdServiceID ORDER BY ls.Modified DESC) AS rnk
FROM Products prod
LEFT JOIN ProductServices ls ON ls.ProductID=prod.ProductID
) x
WHERE rnk = 1
So basically: your join needs to be on ProductID but you only want the most recent ProdServiceID, right?
try this select query please.
Here you get the serviceid which corresponds to productid and the last modiied
SELECT prod.ProductID, prod.Name, prod.ProdExtID, ls.ProdServiceID
FROM Products prod
LEft join ProductServices ls on ls.ProductID=prod.ProductID
inner JOIN (SELECT ProductID, max(Modified) as Modified
FROM
ProductServices group by ProductID) as ls1 ON ls.ProductID =
ls1.ProductID and ls.Modified = ls1.Modified;
I have following query
SELECT YEAR(T.date), MONTH(T.date), T.production, T.lineID, SUM(rework + scrap)
FROM
(SELECT MAX(positionID), date, production, lineID
FROM productionPerPosition
WHERE lineID = 2
AND date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY date) AS T
INNER JOIN linePosition lp ON lp.lineID = T.lineID
INNER JOIN fttErrorType fet ON fet.positionID = lp.positionID
INNER JOIN fttData fd ON fd.errorID = fet.errorID
AND fd.date = T.date
GROUP BY YEAR(T.date), MONTH(T.date)
which gives this result
Now, I would like to group these results by year and month to get sum of production and sum of last column. I've tried this query
SELECT YEAR(T.date), MONTH(T.date), SUM(T.production), T.lineID, SUM(rework + scrap)
FROM
(SELECT MAX(positionID), date, production, lineID
FROM productionPerPosition
WHERE lineID = 2
AND date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY date) AS T
INNER JOIN linePosition lp ON lp.lineID = T.lineID
INNER JOIN fttErrorType fet ON fet.positionID = lp.positionID
INNER JOIN fttData fd ON fd.errorID = fet.errorID
AND fd.date = T.date
GROUP BY YEAR(T.date), MONTH(T.date)
Which gives me
Here production sum is wrong! It seems that GROUP BY from 7th line in first query is ignored.
Any idea how could I get needed result?
Edit: In inner SELECT I have separate production for several different positions (positionID) but I'm using only production from position that has highest positionID
Group has missing grouping columns that why it is resulting in some unexpected result
SELECT YEAR(T.date), MONTH(T.date), SUM(T.production), T.lineID, SUM(rework + scrap)
FROM
(SELECT MAX(positionID), date, production, lineID
FROM productionPerPosition
WHERE lineID = 2
AND date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY date, production, lineID) AS T
INNER JOIN linePosition lp ON lp.lineID = T.lineID
INNER JOIN fttErrorType fet ON fet.positionID = lp.positionID
INNER JOIN fttData fd ON fd.errorID = fet.errorID
AND fd.date = T.date
GROUP BY YEAR(T.date), MONTH(T.date), T.lineID
Has explained in e4c5 comment, you have to add all the unaggregated fields to your GROUP BY. I made it in the inner SELECT and in the main SELECT:
SELECT YEAR(T.date), MONTH(T.date), SUM(T.production), T.lineID, SUM(rework + scrap)
FROM
(SELECT MAX(positionID), date, production, lineID
FROM productionPerPosition
WHERE lineID = 2
AND date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY date, production, lineID) AS T
INNER JOIN linePosition lp ON lp.lineID = T.lineID
INNER JOIN fttErrorType fet ON fet.positionID = lp.positionID
INNER JOIN fttData fd ON fd.errorID = fet.errorID
AND fd.date = T.date
GROUP BY YEAR(T.date), MONTH(T.date), T.lineID
The below one is my query. It's taking 12 seconds for process. I have created the index for T.DataViewId, but it's still taking long time due to Count(distinct()) and Sum. Thanks in Advance.
;WITH my_cte
AS (SELECT T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM dbo.treehierarchy T
LEFT JOIN dbo.dynamicdatatableid DD
ON T.id = DD.hierarchyid
AND T.dataviewid = DD.dataviewid
LEFT JOIN dbo.demo1 D
ON D.[demo1id] = DD.dynamictableid
WHERE T.dataviewid = 2
AND T.parentid = 0
GROUP BY T.id,
T.name)
SELECT name, id, counts, row_num, measure1
FROM (SELECT name,
id,
counts,
Row_number()
OVER(
ORDER BY counts DESC) AS row_num,
measure1
FROM my_cte) innertable
WHERE ( row_num BETWEEN 1 AND 15 )
It looks as if you only need top 15 records of descending counts. It could be done simply like this :
SELECT
TOP 15 T.name AS name,
T.id AS id,
Count(DISTINCT( DD.dynamictableid )) AS counts,
Round(Sum(D.[employees]), 0) AS measure1
FROM
dbo.treehierarchy T
LEFT JOIN
dbo.dynamicdatatableid DD
ON
T.id = DD.hierarchyid
AND
T.dataviewid = DD.dataviewid
LEFT JOIN
dbo.demo1 D
ON
D.[demo1id] = DD.dynamictableid
WHERE
T.dataviewid = 2
AND
T.parentid = 0
GROUP BY
T.id,T.name
ORDER BY
3 DESC
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 have the folowing sql query:
SELECT DISTINCT(tbl_products.product_id), tbl_products.product_title,
tbl_brands.brand_name, tbl_reviews.review_date_added,
NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
ORDER BY tbl_reviews.review_date_added DESC
That needs to filter out any duplicate product_id's unfortunatly selecting tbl_reviews.review_date_added makes each record unique which means DISTINCT will not work anymore.
Is there any otherway of doing this query so that product_id is still unique?
I did do the GROUP BY and the problem is I display the tbl_reviews.review_date_added on a website and it selects the oldest date. I need the newest date.
Regards
With the description given, it's a bit hard to be certain, but if review_date_added is the only problem, it seems like you want the MAX() of that date?
If the following doesn't help, please could you give example data, example output, and a description of how you want the output to be created?
SELECT
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added,
NOW() AS time_now
FROM
tbl_products
INNER JOIN
tbl_reviews
ON tbl_products.product_id = tbl_reviews.product_id
INNER JOIN
tbl_brands
ON tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id,
tbl_products.product_title,
tbl_brands.brand_name
ORDER BY
MAX(tbl_reviews.review_date_added) DESC
Distinct works for the entire row. The parenthesis are just around the field:
distinct (a), b, c === distinct a, b, c
A straightforward solution is group by. You can use min to select the oldest date.
select tbl_products.product_id
, min(tbl_products.product_title)
, min(tbl_brands.brand_name)
, min(tbl_reviews.review_date_added)
, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY
tbl_products.product_id
ORDER BY
min(tbl_reviews.review_date_added) DESC
Note that if a product can have multiple brands, this will pick the lowest one.
Try this:
SELECT pr.product_id, pr.product_title,
bd.brand_name,
(SELECT MAX(rev.review_date_added) FROM tbl_reviews rev
WHERE pr.product_id = rev.product_id) AS maxdate,
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
or (as suggested by #Hogan)
SELECT pr.product_id, pr.product_title,
bd.brand_name, md.maxdate
NOW() AS time_now
FROM tbl_products pr INNER JOIN tbl_reviews re
ON pr.product_id = re.product_id
INNER JOIN tbl_brands bd
ON pr.brand_id = bd.brand_id
INNER JOIN (SELECT product_id, MAX(review_date_added) AS maxdate
FROM tbl_reviews rev GROUP BY product_id) md
ON pr.product_id = md.product_id
GROUP BY pr.product_id
ORDER BY re.review_date_added DESC
I combined the answer of Andomar with some changes you will find here.
SELECT tbl_products.product_id, tbl_products.product_title,
tbl_products.product_date_added, tbl_brands.brand_name,
MAX(tbl_reviews.review_date_added) AS review_date_added, NOW() AS time_now
FROM tbl_products, tbl_reviews, tbl_brands
WHERE tbl_products.product_id = tbl_reviews.product_id AND
tbl_products.brand_id = tbl_brands.brand_id
GROUP BY tbl_products.product_id
ORDER BY MAX(tbl_reviews.review_date_added) DESC
Works beautifully and shows the newest date at tbl_reviews.review_date_added.
Regards