【问题标题】:Learning SQL: Need help Using HAVING to get the MIN result from an aggregate学习 SQL:需要帮助 使用 HAVING 从聚合中获取 MIN 结果
【发布时间】:2017-08-22 03:03:15
【问题描述】:

希望能得到一些帮助。刚接触 SQL 并试图保持头脑清醒。

我接到了这个任务:

“使用 HAVING,确定哪些直接下属的平均工资最低。”

我的逻辑是在一个派生表上进行连接,该表将计算每个拥有直接下属的经理的船员平均工资。然后,此结果将通过 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

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

我知道,从在线查看线程来看,使用 TOP 是一种过滤项目的方法,但尚未引入该方法,我希望保持在迄今为止课程中已建立的参数范围内。

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

谢谢,

J

【问题讨论】:

    标签: sql sql-server subquery min having


    【解决方案1】:

    您需要另一个子查询(如果您不想使用顶部/窗口功能/等):

    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
    

    另一种方法是使用窗口函数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;
    

    【讨论】:

    • Hey GurV,我在网上看过 TOP,但课程中还没有介绍。
    • 是的,我考虑过使用 WHERE。显然,我必须使用 HAVING 来获得结果。这似乎是故意使这个问题变得荒谬。
    • @ROKPLYR - 刚刚用有子查询更新了答案(见第一个)
    • 解决了!感谢您抽出时间来说明这一点。我已经坚持了两天了......
    • @ROKPLYR - 很高兴提供帮助。
    【解决方案2】:

    你应该使用 HAVING 和 equals 来代替 IN 所以类似:

    HAVING Wally.AVGSalary = MIN(Wally.AVGSalary)

    在您使用IN 的情况下,它将返回所有行,并且您只想要薪水等于最低的行。

    【讨论】:

    • HAVING Wally.AVGSalary = MIN(Wally.AVGSalary) 给了我同样的结果
    【解决方案3】:

    试试这个:

    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)       
    

    -- 在临时表变量中使用样本数据:

    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;

    如果直接聘用两个或多个经理的平均工资相同,则具有产生多个结果的优势。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多