学习 SQL:需要帮助使用 HAVING 从聚合中获取 MIN 结果

Learning SQL: Need help Using HAVING to get the MIN result from an aggregate

希望得到一些帮助。 SQL 的新手,努力保持头脑清醒。

我接到了这个任务:

"Using HAVING, determine whose Direct Reports have the lowest Avg Salary."

我的逻辑是对派生的 table 进行联接,该派生的 table 将计算每个有直接下属的经理的工作人员平均工资。然后,此结果将通过 HAVING 子句过滤为 MIN 值。

SELECT Flash.firstname, Flash.lastname, Wally.AVGSalary, 
       Wally.[Direct Reports] FROM CrewMembers Flash
    JOIN
    (
        SELECT Barry.crewMemberId, AVG(Zoom.salary) AS 'AVGSalary', COUNT(Zoom.firstname) AS 'Direct Reports' 
                    FROM CrewMembers Barry
            JOIN CrewMembers Zoom 
                           ON Zoom.managerId = Barry.crewMemberId
        GROUP BY Barry.crewMemberId 
    ) 
    AS Wally ON Wally.crewMemberId = Flash.crewMemberId

GROUP BY Flash.firstname, Flash.lastname, Wally.AVGSalary, Wally.[Direct Reports]

HAVING MIN(Wally.AVGSalary) in (Wally.AVGSalary)

ORDER BY Wally.AVGSalary asc 

我得到这个结果:

firstname   lastname    AVGSalary   Direct Reports
Mike        Patton      33666.500000    2
Kurt        Corgan      37300.000000    2
Amber       Bruckner    45851.666666    3
Doug        Adams       86250.000000    2
Montgomery  Scott       92500.000000    2
James       Kirk        132666.750000   3

我被难住了。我需要它给我 JUST 具有最小值的行,它给了我每个值。我盯着这个看,不知道我做错了什么。

我知道,通过在线查看线程,使用 TOP 是一种过滤项目的方法,但尚未介绍,我想保持在课程中已建立的参数范围内,所以远的。

任何对我所写内容的批评或任何帮助都会很棒。就像我说的,我是新手,只是想跟上。

谢谢,

J

你需要另一个子查询(如果你不想使用 top/window function/etc):

select Flash.firstname,
    Flash.lastname,
    Wally.AVGSalary,
    Wally.[Direct Reports]
from CrewMembers Flash
join (
    select Barry.crewMemberId,
        AVG(Zoom.salary) as 'AVGSalary',
        COUNT(Zoom.firstname) as 'Direct Reports'
    from CrewMembers Barry
    join CrewMembers Zoom on Zoom.managerId = Barry.crewMemberId
    group by Barry.crewMemberId
    having avg(Zoom.salary) = (
            select min(salary)
            from (
                select AVG(Zoom.salary) as salary
                from CrewMembers Barry
                join CrewMembers Zoom on Zoom.managerId = Barry.crewMemberId
                group by Barry.crewMemberId
                ) t
            )
    ) as Wally on Wally.crewMemberId = Flash.crewMemberId

您可以使用 top:

select top 1 Flash.firstname,
    Flash.lastname,
    Wally.AVGSalary,
    Wally.[Direct Reports]
from CrewMembers Flash
join (
    select Barry.crewMemberId,
        AVG(Zoom.salary) as 'AVGSalary',
        COUNT(Zoom.firstname) as 'Direct Reports'
    from CrewMembers Barry
    join CrewMembers Zoom on Zoom.managerId = Barry.crewMemberId
    group by Barry.crewMemberId
    ) as Wally on Wally.crewMemberId = Flash.crewMemberId
order by Wally.AVGSalary

另一种方法是使用 window 函数 rank:

select Flash.firstname,
    Flash.lastname,
    Wally.AVGSalary,
    Wally.[Direct Reports]
from CrewMembers Flash
join (
    select Barry.crewMemberId,
        AVG(Zoom.salary) as 'AVGSalary',
        COUNT(Zoom.firstname) as 'Direct Reports',
        rank() over (order by AVG(Zoom.salary)) as rnk
    from CrewMembers Barry
    join CrewMembers Zoom on Zoom.managerId = Barry.crewMemberId
    group by Barry.crewMemberId
    ) as Wally on Wally.crewMemberId = Flash.crewMemberId
where Wally.rnk = 1;

您应该将 HAVING 与等于而不是 IN 一起使用,例如:

HAVING Wally.AVGSalary = MIN(Wally.AVGSalary)

在你 IN 的情况下,它将 return 所有行,你只想要薪水等于最低的人。

试试这个:

Select crewMemberId, avgSalary
From (Select s.crewMemberId, 
         AVG(d.salary) avgSalary
      From CrewMembers d join CrewMembers s 
         on s.crewMemberId = d.managerId 
      group by s.crewMemberId) x
Where avgSalary = 
   (Select Min(avgSalary) 
    from (Select s.crewMemberId, 
             AVG(d.salary) avgSalary
          From CrewMembers d join CrewMembers s 
              on s.crewMemberId = d.managerId 
          group by s.crewMemberId)x)       

-- 在临时 table 变量中使用示例数据:

declare @e table(crewmemberId int primary key not null, 
              managerId int null, salary decimal)
Insert @e(crewmemberId, managerId, salary)
values (1, null, 23), 
       (2,1,45), (3,1,33), (4,1,80), 
       (5,2,14), (6,2,8), (7,2,12),
       (8,3,11), (9,3,5), (10,3,2), 
       (11,4,51), (12,4,38), (13,4,17) 

Select crewMemberId, avgSalary
From (Select s.crewMemberId, 
         AVG(d.salary) avgSalary
      From @e d join @e s 
         on s.crewMemberId = d.managerId 
      group by s.crewMemberId) x
Where avgSalary = 
   (Select Min(avgSalary)
    From (Select s.crewMemberId, 
            AVG(d.salary) avgSalary
          From @e d join @e s 
             on s.crewMemberId = d.managerId 
          group by s.crewMemberId)x)        

这给出了 crewmemberId = 3, Avg Salary = 6.0000;

如果直接雇用两个或更多经理的平均工资相同,它的优势是产生多个结果。