【问题标题】:Complex MySQL not returning the results I need复杂的 MySQL 没有返回我需要的结果
【发布时间】:2018-04-22 23:10:23
【问题描述】:

tl:博士 我需要从一个表中获取每个员工的最新行,并将其与另一个表中每个员工的多行匹配。我能够从一张表中获取每位员工的最新条目,但无法从第二张表中提取数据。

详情:

前两个表显示了我数据库中的一些代表性数据。此处显示的数据和表格是我的完整架构和数据集的 sn-ps。 (表格:'employees' 和 'employee_payrollhours')

employee_number:这是一个 ID 号,用于识别单个员工 insert_at:这是记录保存到数据库时的日期/时间戳 datetime_in:这是员工开始轮班的日期/时间

SELECT employee_number, last_name, inserted_at FROM employees;
TABLE:  employees
+-----------------+-------------+---------------------+
| employee_number |  last_name  | inserted_at         |
+-----------------+-------------+---------------------+
|       123456789 | Lastone     | 2018-02-26 22:26:38 |
|       123456789 | Lastone     | 2018-03-15 15:16:14 |
|       123456789 | Lastone     | 2018-03-15 20:57:23 |
|       123456789 | Lastone     | 2018-04-16 00:10:27 |
|       223456789 | Lasttwo     | 2018-04-16 03:37:49 |
|       270000001 | Lastthree   | 2018-04-06 22:42:50 |
|       270000001 | Lastthree   | 2018-04-17 14:10:01 |
+-----------------+-------------+---------------------+


SELECT employee_number, datetime_in FROM employee_payrollhours
TABLE:  employee_payrollhours
+-----------------+---------------------+
| employee_number | datetime_in         |
+-----------------+---------------------+
|       123456789 | 2018-04-06 08:00:00 |
|       123456789 | 2018-04-08 08:00:00 |
|       123456789 | 2018-04-10 08:00:00 |
|       123456789 | 2018-04-15 08:00:00 |
|       123456789 | 2018-04-17 08:00:00 |
|       123456789 | 2018-04-19 08:00:00 |
|       223456789 | 2018-04-06 08:00:00 |
|       223456789 | 2018-04-08 08:00:00 |
|       223456789 | 2018-04-10 08:00:00 |
|       223456789 | 2018-04-15 08:00:00 |
|       223456789 | 2018-04-17 08:00:00 |
|       223456789 | 2018-04-19 08:00:00 |
|       270000001 | 2018-04-07 08:00:00 |
|       270000001 | 2018-04-09 08:00:00 |
|       270000001 | 2018-04-11 08:00:00 |
|       270000001 | 2018-04-16 08:00:00 |
+-----------------+---------------------+

从员工中为每个员工获取一行

SELECT * FROM employees GROUP BY last_name

并从员工表中获取每个员工的最新条目。

SELECT * FROM employees e1
WHERE Inserted_at = 
    (SELECT MAX(e2.Inserted_at)
    FROM employees e2
    WHERE e1.Employee_Number = e2.Employee_Number)
+-----------------+-------------+---------------------+
| employee_number |  last_name  | inserted_at         |
+-----------------+-------------+---------------------+
|       123456789 | Lastone     | 2018-04-16 00:10:27 |
|       223456789 | Lasttwo     | 2018-04-16 03:37:49 |
|       270000001 | Lastthree   | 2018-04-17 14:10:01 |
+-----------------+-------------+---------------------+

这就是我想要的。我希望“employees”中每个员工的最新条目与“employee_payrollhours”表中的相应员工数据一起显示。

+-------------------+---------------------+
|     last_name     | datetime_in         |
+-------------------+---------------------+
|       Lastone     | 2018-04-06 08:00:00 |
|       Lastone     | 2018-04-08 08:00:00 |
|       Lastone     | 2018-04-10 08:00:00 |
|       Lastone     | 2018-04-15 08:00:00 |
|       Lastone     | 2018-04-17 08:00:00 |
|       Lastone     | 2018-04-19 08:00:00 |
|       Lasttwo     | 2018-04-06 08:00:00 |
|       Lasttwo     | 2018-04-08 08:00:00 |
|       Lasttwo     | 2018-04-10 08:00:00 |
|       Lasttwo     | 2018-04-15 08:00:00 |
|       Lasttwo     | 2018-04-17 08:00:00 |
|       Lasttwo     | 2018-04-19 08:00:00 |
|       Lastthree   | 2018-04-07 08:00:00 |
|       Lastthree   | 2018-04-09 08:00:00 |
|       Lastthree   | 2018-04-11 08:00:00 |
|       Lastthree   | 2018-04-16 08:00:00 |
+-------------------+---------------------+

这个查询给了我错误“子查询返回超过 1 行”

SELECT employees.*, employee_payrollhours.*
FROM employees, employee_payrollhours
WHERE employee_payrollhours.employee_number = (select employee_number from employees group by last_name);

这个查询给了我混合的数据。

SELECT employees.last_name, employees.employee_number, employee_payrollhours.employee_number, employee_payrollhours.datetime_in
FROM employees, employee_payrollhours
WHERE employee_payrollhours.employee_number = employees.employee_number;

这个查询给了我零个返回结果

SELECT * FROM employees e1, employee_payrollhours
WHERE `e1`.`Inserted_at` = 
    (SELECT MAX(e2.Inserted_at)
    FROM employees e2
    WHERE e1.Employee_Number = e2.Employee_Number)
    AND (`e1`.`Inserted_at` = 
    (SELECT MAX(e2.Inserted_at)
    FROM employees e2
    WHERE e1.Employee_Number = e2.Employee_Number)) = employee_payrollhours.Employee_Number;

有人能给我一些指导,告诉我如何解决这个问题以找到我需要的查询吗?

提前谢谢你。

【问题讨论】:

    标签: mysql


    【解决方案1】:

    当然有很多方法可以做到这一点,我将只介绍其中一种。这里的技巧是从employees 表中获取inserted_at 的最后一个条目。一种方法当然是使用max 进行group by 查询,但是我们将无法加入employee_payrollhours 表。但是,我们可以使用一个技巧,如果我们使用具有更大inserted_at 的条件对自身执行left outer joinemployees,然后仅过滤连接为空的记录,这将为我们提供与a 相同的结果group by 查询,但我们仍然可以加入 employee_payrollhours 并获得想要的结果。

    像这样:

    select e1.*, eprh.* from employees e1
      left outer join employees e2 on
        e1.employee_number = e2.employee_number and
        e2.inserted_at > e1.inserted_at
      left join employees_payrollhours eprh on
        eprh.employee_number = e1.employee_number
    where e2.employee_number is null
    

    【讨论】:

    • 感谢您的快速回复。我已将此代码放入我的 PHP 代码并返回正确的结果,假设我没有忽略某些东西。到目前为止,两种解决方案都非常有效。我选择这个解决方案而不是另一个的唯一原因是这个显示的员工输入了“空”时间,这将允许显示我们的兼职员工,即使他们没有记录任何时间。
    【解决方案2】:

    感谢两位(截至撰写本文时)非常及时的回复。我显然需要更多的 MySQL 练习。

    在 cmets 中,我解释了为什么我选择了我所做的答案。

    我在我的应用程序中尝试了这两种解决方案。我选择的那个允许那些没有进入任何时间的员工仍然被显示。这涵盖了在特定时间段内可能没有工作但仍会显示在结果中的兼职员工。

    【讨论】:

      【解决方案3】:

      我认为这个查询 (SQLFiddle) 会做你想做的事:

      select e.last_name, e.most_recent, p.datetime_in
      from (select employee_number, last_name, max(inserted_at) as most_recent from employees group by employee_number) e
      left join employee_payrollhours p
      on p.employee_number = e.employee_number
      

      输出:

      last_name   most_recent             datetime_in
      Lastone     2018-04-16 00:10:27     2018-04-06 08:00:00
      Lastone     2018-04-16 00:10:27     2018-04-08 08:00:00
      Lastone     2018-04-16 00:10:27     2018-04-10 08:00:00
      Lastone     2018-04-16 00:10:27     2018-04-15 08:00:00
      Lastone     2018-04-16 00:10:27     2018-04-17 08:00:00
      Lastone     2018-04-16 00:10:27     2018-04-19 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-06 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-08 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-10 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-15 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-17 08:00:00
      Lasttwo     2018-04-16 03:37:49     2018-04-19 08:00:00
      Lastthree   2018-04-17 14:10:01     2018-04-07 08:00:00
      Lastthree   2018-04-17 14:10:01     2018-04-09 08:00:00
      Lastthree   2018-04-17 14:10:01     2018-04-11 08:00:00
      Lastthree   2018-04-17 14:10:01     2018-04-16 08:00:00
      

      【讨论】:

      • 感谢您的快速重播。我非常感谢您为此所做的工作,尤其是在摆弄显示的数据和解决方案时。这个解决方案给了我我所要求的结果,但有一个条件我没有真正考虑过。另一个解决方案涵盖了这种情况,而这个没有。然而,这个解决方案很可能是其他人需要的东西。
      • 如果你包含那个条件,我会给出不同的答案,将join 更改为left join 很简单。我已经编辑了我的帖子以反映这一点。
      • 我相信你会的。你是对的,它没有在我的原始帖子中列出。那肯定在我身上。当我写这篇文章时,我没有考虑过这种情况。我向你道歉。对于它的价值,我确实给了你两个+1。不幸的是,我的声望仍然太低,无法显示我的 +1。
      • 没问题,吉姆,我自己也做过同样的事情。感谢您的 +1。
      猜你喜欢
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-21
      • 1970-01-01
      相关资源
      最近更新 更多