【问题标题】:Return information about oldest employee in department, if department has more than 20 employees如果部门有超过 20 名员工,则返回部门中最年长员工的信息
【发布时间】:2016-09-02 16:18:07
【问题描述】:

不要评判我,我是 SQL 查询的新手。我得到了方案,如下图所示。因此,有 2 个表,第一个员工包含 EmployeeID、FirstName、LastName、DateOfBirth 和 DepartmentID。第二个称为 Department ,包含 DepartmentID 和 DepartmentName 。

我想返回包含超过 20 名员工的每个部门中最年长的员工的 FirstName、LastName 和 DepartmentName。

我的解决方案是以下查询:

SELECT FirstName, LastName, DepartmentName
FROM employees
LEFT JOIN department
ON employees.DepartmentID = department.DepartmentID
    WHERE (employees.DateOfBirth = 
(SELECT MIN(employees.DateOfBirth ) FROM (
SELECT *FROM employees WHERE employees.DepartmentID IN ( 
SELECT employees.DepartmentID FROM employees GROUP BY DepartmentID HAVING COUNT(*) > 20)));

我认为这个逻辑很好,因为内部SELECT 语句将返回每个员工人数超过 20 人的部门的 ID,而外部应该返回最老的员工。

我遇到的问题是,当我尝试执行此查询时,它返回SQL error 每个派生表都必须有自己的别名。 我尝试在每个派生表上放置别名,但结果仍然相同。 请帮我解决这个问题。

另外,如果有人有不同的解决方案,请分享。

谢谢。 草莓要求的加法,Create查询

CREATE TABLE Employees
(
EmployeeID int, 
FirstName varchar(10),
LastName varchar(15),
DateOfBirth date,
DeparmentID int
)

CREATE TABLE Department
(
DepartmentID int, 
DepartmentName varchar(15)
)

【问题讨论】:

  • 哇,年龄歧视查询 - SO 上的第一个
  • 如果派生表需要别名,请给它一个别名!就是这么简单。也就是说,这是一个丑陋的查询。
  • 该吃午饭了 - 评论已删除
  • 因为 MIN() 将返回最早的出生日期
  • 如果您愿意,请考虑遵循以下简单的两步操作: 1. 如果您还没有这样做,请提供适当的 CREATE 和 INSERT 语句(和/或 sqlfiddle),以便我们可以更容易复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。

标签: mysql sql subquery


【解决方案1】:

由于格式不一致,您的查询难以阅读。所以我会清理如下:

SELECT  FirstName, LastName, DepartmentName
FROM    employees
        LEFT JOIN department
        ON employees.DepartmentID = department.DepartmentID
WHERE   (employees.DateOfBirth = 
        (
        SELECT  MIN(employees.DateOfBirth)
        FROM    (
                SELECT  *
                FROM    employees
                WHERE   employees.DepartmentID IN (
                        --Departments with more than 20 employees
                        SELECT  employees.DepartmentID
                        FROM    employees
                        GROUP BY DepartmentID
                        HAVING COUNT(*) > 20)
                ) -- You need an alias here.
                  -- Also from this point you were missing closing brackets.

您的查询有问题:

  • 显然缺少别名和右括号意味着您甚至无法测试您的查询。
  • 同样SELECT MIN(employees.DateOfBirth) 只返回一个值。不是每个部门的值。
  • 因此,您的总体结果仅包括所有“大”部门中最年长的员工。 (除非每个部门中年龄最大的员工恰好有相同的出生日期。)
  • 如果任何员工的出生日期恰好与大部门中最老的相同,它还可以包括来自较小部门的结果。而且那个员工甚至不需要是他们部门中最年长的!
  • 使用过多的子查询也会导致效率低下。

CTE(通用表表达式)非常适合简化复杂的查询。但我不知道mysql是否支持它们。所以这个解决方案仍然使用子查询。

SELECT  e.FirstName, e.LastName, d.DepartmentName
FROM    employees e -- I prefer short aliases
        INNER JOIN (
        -- This sub-query returns the earliest birth date within each
        -- big department. This needs to be an aliased query so you
        -- can join to other tables for your desired columns.
        SELECT  DepartmentID, MIN(DateOfBirth) AS MinDOB -- Must alias column
        FROM    employees
        WHERE   DepartmentID IN (
                -- Big departments
                SELECT  DepartmentID
                FROM    employees
                GROUP BY DepartmentID
                HAVING COUNT(*) > 20
                )
        GROUP BY DepartmentID
        ) ddob -- Alias Department Date of Birth
        -- As a result of inner joining to ddob your employees
        -- will be filtered to only those that match the relevant
        -- ones identified in the query.
        ON  e.DepartmentID = ddob.DepartmentID
        AND e.DateOfBirth = ddob.MinDOB
        INNER JOIN Department d
        ON  d.DepartmentID = e.DepartmentID

上述解决方案中需要注意的一点,如果一个部门有 2 名员工因年龄最大而被并列,则两者都会被退回。

这种方法在结构上与您的方法相似,但您也可以从另一个方向解决问题。

  • 开始让所有部门中最年长的员工。
  • 并且仅在最后根据部门规模过滤结果。

我会留给你去尝试。我怀疑查询会更简单一些。

【讨论】:

    【解决方案2】:

    以下 SQL 脚本对应于您的类图:

    CREATE TABLE Departments (
     DepartmentID int AUTO_INCREMENT PRIMARY KEY, 
     DepartmentName varchar(15)
    );
    
    CREATE TABLE Employees (
     EmployeeID int AUTO_INCREMENT PRIMARY KEY, 
     FirstName varchar(10),
     LastName varchar(15),
     DateOfBirth date,
     DepartmentID int,
     FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
    );
    

    根据您的类图,每个员工都有一个部门。所以,这就是使用INNER JOIN 的原因。我认为以下查询可以满足您的要求:

    SELECT ee.FirstName, ee.LastName, ee.DateOfBirth, t.DepartmentName 
    FROM
    ( 
         SELECT e.DepartmentID, d.DepartmentName, MIN(e.DateOfBirth) AS DateOfBirth 
         FROM Employees AS e
         INNER JOIN Departments AS d ON e.DepartmentID = d.DepartmentID
         WHERE e.DepartmentID IN (
             SELECT DepartmentID 
             FROM Employees 
             GROUP BY DepartmentID HAVING COUNT(DepartmentID) > 20
         )
         GROUP BY e.DepartmentID
    ) AS t
    INNER JOIN Employees AS ee
    WHERE ee.DepartmentID = t.DepartmentID AND ee.DateOfBirth = t.DateOfBirth
    

    输出示例:

    FirstName   LastName    DateOfBirth DepartmentName
    fisrt14     last14      02/01/2000  SI
    fisrt31     last31      12/01/2003  Finance
    

    你提高了它的性能!

    【讨论】:

    • 您的答案不正确。条件AND e.DateOfBirth = (SELECT MIN(DateOfBirth) from Employees); 意味着您最多会返回一个在整个公司中年龄最大的员工。 IE。除非他在所有部门中也是最年长的,否则您不会返回部门中最年长的人。
    猜你喜欢
    • 1970-01-01
    • 2013-05-23
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多