Problems with Group By - want to call a column without using in Group By (T-SQL, SQL Server)

StackOverflow https://stackoverflow.com/questions/21976532

  •  15-10-2022
  •  | 
  •  

Question

I want to be able to select the top Max(HR) leaders by LgID and YearID. But I also want the Player's name column. (T-SQL, SQL Server 2012 Express)

When I query with the player name it returns '0' for every Max(HR) output. It seems SQL Server 2012 Express won't allow me to omit the PlayerID in the group by when I have it in the select statement. Is there a way to get by this? A Case when? Or something else?

Select
    playerID,
    yearID,
    lgID,
    Max(HR) HR_Leader
from batting
group by
    yearID,
    lgID
order by
    yearID desc,
    lgID,
    Max(HR)

Returns this error:
Msg 8120, Level 16, State 1, Line 2
Column 'batting.playerID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

But when I comment out the PlayerID, it runs, but I have no name, as seen here:

Select
    --playerID,
    yearID,
    lgID,
    Max(HR) HR_Leader
from batting
group by
    yearID,
    lgID
order by
    yearID desc,
    lgID,
    Max(HR)

yearID  lgID    HR_Leader
2013    AL  53
2013    NL  36
2012    AL  44
2012    NL  41
2011    AL  43
2011    NL  39
2010    AL  54
2010    NL  42
2009    AL  39
2009    NL  47

Update after 1st comment/question.

Select
    playerID,
    yearID,
    lgID,
    Max(HR) HR_Leader
from batting
group by
    playerID,
    yearID,
    lgID
order by
    yearID desc,
    lgID,
    Max(HR) desc


Query Returns this: Which doesn't have the look of the 1st output (

playerID    yearID  lgID    HR_Leader
davisch02   2013    AL  53
cabremi01   2013    AL  44
encared01   2013    AL  36
dunnad01    2013    AL  34
trumbma01   2013    AL  34
jonesad01   2013    AL  33
longoev01   2013    AL  32
ortizda01   2013    AL  30
mossbr01    2013    AL  30
beltrad01   2013    AL  30

What I want is this:

PlayerID      yearID    lgID    HR_Leader
Player1       2013          AL  53
Player2       2013          NL  36
Player3       2012          AL  44
Player4       2012          NL  41
Player5       2011          AL  43
Player6       2011          NL  39
Player7       2010          AL  54
Player8       2010          NL  42
Player9       2010          NL  42
Was it helpful?

Solution

Here a simple way. Use a common table expression (CTE) to get the top HR for each League and Year. Then join that back to batting to get the players that own the those numbers. The sample data includes a tie which returns both players in no particular order.

CREATE TABLE batting (playerID INT, yearID INT, lgID CHAR(2), HR INT)

INSERT INTO batting 
SELECT 1, 2010, 'AL', 40 UNION
SELECT 2, 2010, 'AL', 35 UNION
SELECT 3, 2010, 'NL', 35 UNION
SELECT 4, 2010, 'NL', 30 UNION
SELECT 5, 2011, 'AL', 50 UNION
SELECT 6, 2011, 'AL', 45 UNION
SELECT 3, 2011, 'NL', 45 UNION
SELECT 7, 2011, 'NL', 45 UNION
SELECT 4, 2011, 'NL', 40

;WITH cte AS (
  SELECT yearID
        ,lgID
        ,MAX(HR) HR_Leader
    FROM batting
   GROUP BY yearID
           ,lgID
) 
  SELECT playerID
        ,c.*
    FROM batting b
         INNER JOIN
         cte c ON b.yearID=c.yearID
              AND b.lgID=c.lgID
              AND b.HR=c.HR_Leader
   ORDER BY c.yearID DESC
           ,c.lgID

DROP TABLE batting
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top