SQL Puzzle – Correct the Incorrect Query – Win Price Worth USD 1000 – Aggregate and Subquery

SQL Puzzle - Correct the Incorrect Query - Win Price Worth USD 1000 - Aggregate and Subquery puzzle It has been a while since we have seen a puzzle so let us do a small puzzle today. Actually, this is a very simple puzzle if you have worked with SQL Server for a while. I got an email from one of the readers from the blog post and he wanted me to correct the following query which he had written. Well, I have been working with SQL Server for over 19 years and I often do not remember the syntax and have to look up online. Here is a very simple puzzle for you which involves Aggregate and Subquery.

Important Update: The Workshop is now over and it was one of the landmark workshops, where I shared business secrets of successful Performance Tuning Expert. You can watch the recording of the workshop for a limited period of time.

Puzzle – Aggregate and Subquery

Here is the query when we run against the AdventureWorks database, it gives us an error. Remember AdventureWorks database is a sample database and you can download and install AdventureWorks over here.

USE AdventureWorks2014
GO
SELECT pch.StandardCost, p.ProductID
FROM Production.ProductCostHistory pch
INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
WHERE pch.StandardCost > AVG(p.StandardCost)
GO

Now when you run the above query, it gives us the following error:

Msg 147, Level 15, State 1, Line 17
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.

Now here is your task, you need to help me to fix the above query. The hint to resolve the query is already in the blog post’s title and in the query error. You need to understand what my query is attempting to do and use the hint which is already pointed out to you. After you successfully fix the query it will produce the following results.

SQL Puzzle - Correct the Incorrect Query - Win Price Worth USD 1000 - Aggregate and Subquery correctresult

Rules

Well, there are no real rules, as long as you modify my query to get me above results. Please post your query in the comments section below before April 22, 2019. I will keep all the answers hidden till April 22, 2019 11:59:00 PM.

Winner

One Winner will get 1 free seat for my upcoming class, which is worth USD 1000.

SQL Server Performance Tuning Practical Workshop for EVERYONE
Date: April 23, 2019, Tuesday
8:00 AM Pacific Time | 11:00 AM Eastern Time

If you do not want to take part in the contest, you can directly register for the class here.

Update: April 23, 2019

The contest is closed and the winning Answer is here:

USE AdventureWorks2014
GO
SELECT pch.ProductID, pch.StartDate,pch.EndDate, pch.StandardCost, pch.ModifiedDate
FROM Production.ProductCostHistory pch
INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
WHERE pch.StandardCost > p.StandardCost
GO

There is no need for the AVG on the StandardCost as there will be always a single entry for the product. Even if you change the query with group by + having you will still see the query uses the simple join.

Congratulations to the winner Nicholas Månsson. He is very excited to join the SQL Server Performance Tuning Practical Workshop for EVERYONE.

Everyone who participated you got to solve this difficult puzzle so indirectly you are a winner (of knowledge) as well. This was an intense competition with over 500 comments.

Reference: Pinal Dave (https://blog.sqlauthority.com)

Contest, SQL Scripts, SQL Server
Previous Post
SQL SERVER – Relating Unrelated Tables – A Question from Reader
Next Post
Puzzle – DELETE Qualified Rows From Multiple Tables – Win USD 1000 Worth Class

Related Posts

527 Comments. Leave new

  • SELECT pch.ProductID, pch.StartDate, pch.endDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch join (select ProductID, AVG(StandardCost) AvgStandardCost FROM Production.ProductCostHistory group by ProductID) p
    on pch.ProductID = p.productID
    where pch.StandardCost > p.AvgStandardCost and pch.enddate is not null and pch.ProductID NOT IN (select productid from Production.Product where SellEndDate is not null)

    –This should Provide the results you are looking for. However what you were looking for was not clear, but the results provided gave a hint… Hopefully this is acceptable. I’m interested in the final solution… look forward to seeing it.

    Reply
  • Hi Pinal,
    Please accept this query as my answer.

    SELECT p.ProductID, pch.StartDate, pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > p.StandardCost

    Thanks

    Although my previous query was also working but that was using sub query. But now I got the working query without subquery.

    Reply
  • select ph.ProductID
    ,ph.StartDate
    ,ph.EndDate
    ,ph.StandardCost
    ,ph.ModifiedDate

    from
    (
    SELECT avg(StandardCost) stdcost, ProductID
    FROM Production.Product
    group by ProductID
    ) p
    INNER JOIN Production.ProductCostHistory ph ON ph.ProductID = p.ProductID
    WHERE ph.StandardCost > p.stdcost

    Reply
  • Hi Pinal,

    Above result can be get without AVG function, result is given by below query

    SELECT p.ProductID,startdate,enddate,pch.StandardCost,pch.modifieddate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    where pch.StandardCost >p.StandardCost

    Reply
  • Muhammad Ishaq
    April 22, 2019 6:01 pm

    USE AdventureWorks
    GO
    SELECT pch.ProductID, pch.StartDate,pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > p.StandardCost
    GO

    Reply
  • Andreas Etelkozi
    April 22, 2019 6:07 pm

    —- Solution 1 – the ‘raw result’
    USE AdventureWorks2014
    GO
    SELECT p.ProductID, pch.[StartDate], pch.[EndDate], pch.StandardCost, pch.[ModifiedDate]
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > (SELECT AVG(p.StandardCost) FROM [Production].[Product] p)
    GO

    —- Solution 2 – ‘enddate’-restricted result
    USE AdventureWorks2014
    GO
    SELECT p.ProductID, pch.[StartDate], pch.[EndDate], pch.StandardCost, pch.[ModifiedDate]
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > (SELECT AVG(p.StandardCost) FROM [Production].[Product] p)
    AND pch.Enddate IS NOT NULL
    GO

    Reply
  • Muhammad Ishaq
    April 22, 2019 6:19 pm

    in the given puzzle, you are trying to average the p.StandardCost which is not need because it is always one and only one record against p.ProductID (because it is primary key for Table Product).

    first solution: just remove the evg function and query is look like this

    USE AdventureWorks
    GO
    SELECT pch.ProductID, pch.StartDate,pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    where pch.StandardCost > p.StandardCost

    GO

    second sol: if you want to put Avg function and want to run query then you should add group by clause and pass all select list and than replace where clause to Having. query is look like this

    USE AdventureWorks
    GO
    SELECT pch.ProductID, pch.StartDate,pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    group by pch.StandardCost, pch.ProductID, pch.StandardCost, pch.EndDate, pch.ModifiedDate, pch.StartDate
    Having pch.StandardCost > avg(p.StandardCost)

    GO

    Reply
  • Here is my answer.

    SELECT p.ProductID, pch.StartDate, pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    CROSS APPLY
    (
    SELECT sub.ProductID, AVG(sub.StandardCost) AS AvgStandardCost FROM Production.Product sub
    WHERE sub.ProductID = pch.ProductID
    GROUP BY sub.ProductID
    ) p
    WHERE pch.StandardCost > p.AvgStandardCost
    GO

    Output is as expected as you mentioned in the blog.

    Reply
  • I’m using AdventureWorks2008R2, but the tables are the same. Here is my query:

    use AdventureWorks2008R2
    go
    SELECT
    p.ProductID
    ,pch.StartDate
    ,pch.EndDate
    ,pch.StandardCost
    –,p.AvgStandardCost
    ,pch.ModifiedDate

    FROM
    Production.ProductCostHistory pch
    INNER JOIN
    (
    select
    Production.Product.ProductID
    ,AVG(Production.Product.StandardCost) as AvgStandardCost
    from
    Production.Product
    group by Production.Product.ProductID
    )p ON pch.ProductID = p.ProductID
    WHERE
    pch.StandardCost > p.AvgStandardCost

    Reply
  • AvgStandardCost is calculated, but commented out in the SQL query – Gil

    Reply
  • SELECT pch.StandardCost, p.ProductID
    FROM Production.ProductCostHistory pch
    where exists
    (select p.ProductID from Production.Product p where pch.ProductID = p.ProductID
    group by p.productid having pch.StandardCost > AVG(p.StandardCost))

    Reply
  • Yelena Shmidt
    April 22, 2019 6:39 pm

    SELECT pch.StandardCost, p.ProductID
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    CROSS APPLY (select AVG(StandardCost) as AvgStdCost from Production.ProductCostHistory) A
    WHERE pch.StandardCost > A.AvgStdCost

    Reply
  • Farhaneh Nazemi
    April 22, 2019 6:51 pm

    USE AdventureWorks2014
    GO
    SELECT pch.*
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    inner join (select AVG(StandardCost) as avg_StandardCost,ProductId from Production.ProductCostHistory Group by ProductId)pc on p.ProductId=pc.ProductId
    WHERE pch.StandardCost > avg_StandardCost
    and pch.StandardCost != avg_StandardCost
    and EndDate is not null
    and Isnumeric(P.Size)1
    order by productId
    GO

    Reply
  • shree niwas kushwah
    April 22, 2019 6:53 pm

    USE AdventureWorks2014
    GO
    SELECT pch.StandardCost, p.ProductID
    FROM Production.ProductCostHistory pch
    INNER JOIN (SELECT P.ProductID,AVG(p.StandardCost) AVG_StandardCost FROM Production.Product p GROUP BY P.ProductID)p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > P.AVG_StandardCost
    GO

    Reply
  • Abhishek Verma
    April 22, 2019 6:56 pm

    SELECT pch.StandardCost, p.ProductID
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost >
    (select AVG(t.StandardCost) from Production.Product t where t.ProductID = pch.ProductID )

    Reply
  • Madhusudhana ERAPPAREDDY
    April 22, 2019 7:19 pm

    USE AdventureWorks2014
    GO
    SELECT pch.StandardCost, p.ProductID, AVG(p.StandardCost)
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    group by pch.StandardCost, p.ProductID
    having pch.StandardCost > AVG(p.StandardCost)
    GO

    Reply
  • Nepram Meitei
    April 22, 2019 7:26 pm

    SELECT pch.*
    FROM Production.ProductCostHistory pch
    WHERE exists
    (select StandardCost from Production.Product p
    WHERE pch.ProductID = p.ProductID
    AND p.standardcost 0
    )

    Reply
  • Hi Pinal,

    Though I am late, please find below fix.

    WITH CTE
    AS
    (
    SELECT P.ProductID,AVG(P.StandardCost) AVG_StandardCost
    FROM Production.Product p
    GROUP BY P.ProductID
    )
    SELECT pch.StandardCost, p.ProductID
    FROM Production.ProductCostHistory pch
    INNER JOIN CTE p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > AVG_StandardCost

    Thanks,
    Anees Ahmed

    Reply
  • Jeevan Dharma Raj
    April 22, 2019 7:50 pm

    Hello Pinal,

    Hope you are doing well.

    Below are my 2 queries for the required output,

    USE AdventureWorks
    GO

    SELECT p.ProductID, pch.StartDate, pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    WHERE pch.StandardCost > (p.StandardCost)
    GO

    SELECT p.ProductID, pch.StartDate, pch.EndDate, pch.StandardCost, pch.ModifiedDate
    FROM Production.ProductCostHistory pch
    INNER JOIN Production.Product p ON pch.ProductID = p.ProductID
    GROUP BY p.ProductID, pch.StartDate, pch.EndDate, pch.StandardCost, pch.ModifiedDate
    Having pch.StandardCost > avg(p.StandardCost)
    GO

    Reply
  • WITH pch
    AS
    (
    SELECT StandardCost, ProductID
    FROM Production.ProductCostHistory
    ),
    p as
    ( Select ProductID, AVG(StandardCost) as StandardCost
    FROM Production.Product
    GROUP By Product.ProductID
    )
    SELECT pch.StandardCost, p.ProductID
    FROM pch
    INNER JOIN p ON p.ProductID = pch.ProductID
    WHERE pch.StandardCost > p.StandardCost
    GO

    Reply

Leave a Reply