1

我有一个看起来像这样的表:

emp_id | code   | min  
1234   | TLPAID | 480  
4321   | TLPAID | 480  
4321   | UPAB   | 4  
4321   | UUAB   | 50  
5555   | TLPAID | 480  
5555   | ALLEUP | 10  

...有数百个可能的代码,但我有兴趣将其中的 6 个相加并检查它是否小于 10。

我有一个查询:

SELECT emp_id, sum(min) as time, SEC_TO_TIME(sum(min)*60) as time_formatted 
FROM codes 
WHERE code IN ('ALLEPD',  'ALLEUP',  'LATEBL',  'NCNS',  'UPAB',  'UUAB') 
GROUP BY emp_id HAVING time < 10 

这个查询很好用,除非员工没有这 6 个代码——那么它们显然不会被返回。这就是我的问题:我需要他们出现在结果中,因为他们的时间是 0,小于 10。

现在,员工将始终拥有 code TLPAID,所以我想知道是否有办法将该代码包含在上面提到的 6 中(这样员工将包含在查询结果中),但仍然只能将这 6 个相加?

期望的结果:

emp_id | min  
1234   | 0  
4321   | 54  
5555   | 10  

关于我应该如何处理这个问题的任何想法?

4

5 回答 5

2

一种方法是从代码表中获取所有 emp_id 的列表,并将该列表用作 LEFT JOIN 操作的“驱动”表。

像这样的东西:

SELECT e.emp_id
     , IFNULL(SUM(c.min),0) AS time
     , SEC_TO_TIME(IFNULL(SUM(c.min),0)*60) AS time_formatted
  FROM (SELECT d.emp_id FROM codes d GROUP BY d.emp_id) e
  LEFT
  JOIN codes c
    ON c.emp_id = e.emp_id
   AND c.code IN ('ALLEPD',  'ALLEUP',  'LATEBL',  'NCNS',  'UPAB',  'UUAB')
 GROUP 
    BY e.emp_id
HAVING time < 10

笔记:

lineview 中的查询e获取 distinct 列表emp_id。我们可以将该查询放在括号中,并在 FROM 子句中使用它,就像它是一个表一样。我们需要为e这个派生表分配一个别名(在这种情况下,我们刚刚选择了 )。

LEFT JOIN返回每个emp_idfrom e,以及匹配的行from codes。(我们选择给该表引用一个别名c。)

WHERE 子句中的谓词与将代码中的行与 e 中的行“匹配”的谓词一起移至 JOIN 的 ON 子句。

SUM()我们将表达式包装在一个函数中,以在为 NULLIFNULL时返回零。SUM()

我们在所有列引用上添加表别名,以 1)避免“模糊列”错误,并且(可能更重要的是)帮助读者破译查询正在做什么,读者不会想知道列引用所指的是哪个表。

(为避免返回 NULL emp_id,我们可以将 a 添加WHERE d.emp_id IS NOT NULL到内联视图查询中。)

于 2013-08-14T19:30:28.583 回答
1

作为我其他答案中方法的替代方法,另一种获得相同结果的方法,没有内联视图和 JOIN 操作:

SELECT c.emp_id
     , SUM( 
         IF(c.code IN ('ALLEPD','ALLEUP','LATEBL','NCNS','UPAB','UUAB'),c.min,0)
       ) AS time
     , SEC_TO_TIME(SUM(
         IF(c.code IN ('ALLEPD','ALLEUP','LATEBL','NCNS','UPAB','UUAB'),c.min,0)
       )*60) AS time_formatted 
  FROM codes c
 GROUP BY c.emp_id
HAVING time < 10

这将扫描代码表中的所有行;没有谓词限制将返回哪些行,因此我们将从表中获取所有emp_idcodes

“技巧”在 SELECT 列表中,我们SUM在其中从IF表达式返回。只要在列表中,IF表达式就会返回列的值。对于 的其他值,表达式返回 0。mincodecode

如果我们曾经有一个给定emp_id的行,其中该 emp_id 的所有行都有一个code出现在列表中,并且NULL作为 的值,min那么这个查询将返回一个NULLSUM(只要 emp_id 至少有一行代码不在列表中,或者至少一行代码在列表中的代码不是 NULL 值,这不会有问题。)

于 2013-08-14T20:05:36.100 回答
1

我可能会将它们分别合并,如下所示:

SELECT emp_id, sum(min) as time, SEC_TO_TIME(sum(min)*60) as time_formatted FROM codes WHERE code IN ('ALLEPD',  'ALLEUP',  'LATEBL',  'NCNS',  'UPAB',  'UUAB') GROUP BY emp_id HAVING time < 10 

UNION

SELECT emp_id, 0 as time, 0 as time_formatted FROM codes WHERE code NOT IN ('ALLEPD',  'ALLEUP',  'LATEBL',  'NCNS',  'UPAB',  'UUAB') GROUP BY emp_id 
于 2013-08-14T19:29:09.353 回答
0

使用当前查询与原始表进行左联接,这将识别不匹配列的返回 null 值,然后将 null 转换为零,这样您的查询也会自动为不匹配的记录求和零,其他匹配的结果将是您当前的查询结果。. PFB 代码

SELECT e.emp_id , IFNULL(SUM(c.min),0) AS time , SEC_TO_TIME(IFNULL(SUM(c.min),0)*60) AS time_formatted FROM (SELECT d.emp_id FROM codes d GROUP BY d. emp_id) e LEFT JOIN 代码 c ON c.emp_id = e.emp_id AND c.code IN ('ALLEPD', 'ALLEUP', 'LATEBL', 'NCNS', 'UPAB', 'UUAB') GROUP BY e.emp_id有时间 < 10

于 2013-08-14T19:42:39.653 回答
0

虽然我可能更喜欢 spencer7593 提供的连接解决方​​案,但我还是想展示一种替代方法:

SELECT 
    `emp_id`,
    SUM(CASE WHEN `code` IN('ALLEPD','ALLEUP','LATEBL','NCNS','UPAB','UUAB') 
        THEN COALESCE(`min`, 0) 
        ELSE 0 END) as `time`, 
    SEC_TO_TIME(SUM(`min`)*60) as `time_formatted` 
FROM `codes`
GROUP BY `emp_id`;

输出:

emp_id  time    time_formatted
1234    0       08:00:00
4321    54      08:54:00
5555    10      08:10:00

在使用以下方法初始化的 mysql 数据库中进行测试:

DROP DATABASE IF EXISTS `SO`;
CREATE DATABASE `SO`;
USE `SO`;

CREATE TABLE `codes` (
    `emp_id` INT,
    `code` VARCHAR(8),
    `min` int
);

INSERT INTO codes (`emp_id` , `code` , `min`)
VALUES
 (1234 , 'TLPAID' , 480)
,(4321 , 'TLPAID' , 480)
,(4321 , 'UPAB' , 4)
,(4321 , 'UUAB' , 50)
,(5555 , 'TLPAID' , 480)
,(5555 , 'ALLEUP' , 10);
于 2013-08-14T20:00:44.090 回答