如何在另一个查询结果上进行查询?

3

我有一个问题,因为我不太擅长查询。

我有一个查询,包含两个选择查询的联合:

   SELECT em.emp_code,  
          em.emp_name,  
          COALESCE(SUM(pe.hours_allotted),0) AS hours,  
          pe.dated 
     FROM employee_master em
LEFT JOIN project_employee pe ON (pe.Emp_code = em.emp_code)
    WHERE (dated >= '2011-03-14'
      AND dated < '2011-03-20' ) 
       OR dated IS NULL 
 GROUP BY em.emp_code 
UNION
  (SELECT em.emp_code,
          em.emp_name,
          '0' AS hours,
          pe.dated
     FROM employee_master em
LEFT JOIN project_employee pe ON (pe.Emp_code = em.emp_code)
    WHERE (dated >= '2011-03-14'
      AND dated < '2011-03-20' ) 
       OR dated IS NOT NULL 
 GROUP BY em.Emp_code)
ORDER BY emp_name;

现在,结果集返回的示例如下:
ecode  ename    hours 
----------------------
201   Alak basu  10 
201 alak basu    0

第一个结果来自于联合查询中第一个select语句,其中hours = 10,而hours = 0则来自于联合查询中第二个select语句。
我的要求是:
ecode     ename       hours 
----------------------------
201      alak basu     10

比如说,对于每个ecode应该只有一个结果。如何对它进行分组,例如按ecode分组汇总工作时间,以便只返回如上所示的一个结果?


为什么你的数据会这么糟糕,出现了同名但大小写不同的情况? - Ignacio Vazquez-Abrams
我觉得这里存在一个需要解决的逻辑错误。如果一个员工在给定的时间范围内有一个“dated”字段,它将匹配两个查询,并存在于联合的两侧。我有一种感觉,这不是预期的效果。这个查询的预期效果到底是什么? - jdmichal
@jdmichal,实际上我的意图是我们有一个基于出勤的任务,需要每天填写谁在工作以及工作了多长时间...现在暂时我们需要知道从3月14日到3月19日这段时间内,有多少人正在工作,他们中有哪些人的工作时间超过6小时... (注:只有那些在特定日期工作的员工才会被计入项目员工...) - Joy
这就是一些日期字段尽管使用了左连接仍然为空的原因...但除此之外,他们的日期字段不为空...并且他们工作了超过6个小时...所以我不得不将逻辑分成两部分,因此我需要使用联合查询。也许我无法完全正确地解释整个情况,但这就是实际情况。 - Joy
是的,但如果您只是让一个员工的工时为 (NULL),COALESCE 将把它转换为零。由于您正在执行 LEFT JOIN,每个员工都将被表示,如果他们没有匹配的 project_employees 行,则他们的工时将为 NULL。因此,再次强调,UNION 的第二部分没有任何作用。请参见我的答案以获取 SQL 应该如何更新的更新。 - jdmichal
2个回答

2
如果期望的结果是将单个员工代码的所有小时数汇总到一行中,并且在UNION后的第二个查询只会返回零小时,那么最好的解决方案似乎是去掉UNION

编辑:进一步澄清后,以下是我认为SQL语句应该如何编写:

SELECT em.emp_code,
       em.emp_name,
       COALESCE(pe.hours, 0) AS hours
FROM employee_master em
LEFT JOIN (
    SELECT emp_code,
           SUM(hours_allotted) AS hours
    FROM project_employee
    WHERE dated >= '2011-03-14' AND
          dated < '2011-03-20'
    GROUP BY emp_code
    ) pe ON (pe.emp_code = em.emp_code)
ORDER BY em.emp_name;

它的功能:

  1. 执行子查询以过滤所有project_employee条目,将其限制在指定的日期范围内。(请注意,在这里根本不需要NULLNOT NULL检查。要么日期在范围内,要么不在范围内。)
  2. 对子查询中生成的每个员工代码的小时数进行求和。
  3. 获取employee_master表中的所有员工,并在过滤和汇总的project_employee子查询结果集中查找匹配的条目。(由于它是一个LEFT JOIN,因此主表中的每个员工都会有一个条目,即使没有任何过滤的project_employee条目匹配。)
  4. 如果没有匹配项,则pe.hours列将为NULL,导致COALESCE回到其第二个值零。
  5. emp_name排序结果。

@jdmichal 但问题是我有两个具有完全不同条件的集合...一个将日期视为空,另一个将日期视为非空....所以我也无法摆脱union :( - Joy
如果它们是不同的条件,那么为什么你的例子会给出相同的员工两次?或者这就是问题所在吗? - jdmichal
@jdmichal,+1 同意。第二部分似乎不是必需的,而且在这种情况下,也可以使用 case 语句。 - Adriaan Stander
@jdmichal 我尝试了你的查询,但是在 MySQL 上出现了错误...不确定是什么原因 :( - Joy
@Joy,我已经修复了几个小的语法问题。(SELECT列表中多余的终止逗号和查询末尾缺少的分号。)目前它通过了MSSQL语法检查器。我没有MySQL实例进行测试。 - jdmichal
@jdmichal 嗯,我已经修好了...再次感谢,只是有一些小问题...我已经解决了 :) - Joy

2

你可以随时执行以下操作:

select emp_code, min(emp_name) as emp_name, sum(hours)
from (
  <your original query here>
) as e
group by emp_code
order by emp_name;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接