MYSQL:SQL查询仅在所有行满足条件时返回行

时间:2013-09-26 05:51:26

标签: mysql sql

考虑三个表 -

  users

    id      |   type
 -----------|------------
    1       |   a
    2       |   b   
    3       |   c

 types  

    id      |   type
 -----------|------------
    a       |   X
    a       |   Y   
    b       |   X
    c       |   X
    c       |   Y
    c       |   Z

 training_status

    id      |   training|   status
 -----------|-----------|-------------
    1       |   X       |   F
    2       |   X       |   S
    2       |   Y       |   S
    3       |   X       |   F
    3       |   Y       |   S

每个用户都有一个类型,类型定义了特定类型的每个用户必须完成的培训。

training_status包含用户已完成的所有培训及其结果(S,F)的状态。用户尚未参加培训,不会有任何培训。

我想找出所有已成功完成所有培训的用户。

这是我正在考虑的方向:

select
  id
from users
  join types
    using (type)
  left join training_status
    using (id,type)
where status NOT IN(None, F);

显然这不是正确的查询,因为即使用户已完成其中一项培训,我们也会获得该行。在前面提到的例子中,我想得到id = 2,因为他已经完成了两种类型的训练。

4 个答案:

答案 0 :(得分:6)

尝试

SELECT DISTINCT u.id
  FROM users u JOIN types t
    ON u.type = t.type LEFT JOIN training_status s
    ON u.id = s.id AND t.training = s.training
 WHERE s.status IS NOT NULL 
 GROUP BY u.id
HAVING COUNT(t.type) = SUM(CASE WHEN s.status = 'S' THEN 1 ELSE 0 END)

SELECT DISTINCT u.id
  FROM users u JOIN types t
    ON u.type = t.type LEFT JOIN training_status s
    ON u.id = s.id AND t.training = s.training
 GROUP BY u.id
HAVING MAX(s.status IS NULL OR s.status = 'F') = 0

输出:

+------+
| id   |
+------+
|    2 |
+------+

这是 SQLFiddle 演示

答案 1 :(得分:0)

试试这个

SELECT *
FROM users
WHERE id NOT IN (
SELECT u.id
  FROM users u 
  JOIN types t 
    ON u.type = t.type 
  LEFT JOIN training_status s
    ON u.id = s.id AND t.training = s.training
 WHERE s.status IS NULL OR s.status = 'F')

答案 2 :(得分:0)

试试这个

select distinct
  u.id
from users u
  left join types t
    on u.type = t.type
  left join training_status ts
    on ts.training = t.training
where ts.status is not null
    and ts.status != 'F'

答案 3 :(得分:0)

这应该有效:

SELECT id 
FROM users
WHERE id not in (SELECT x.id FROM (SELECT u.id AS id, t.type AS type, 'S' AS status
                FROM users u, types t
                WHERE u.type = t.id
                EXCEPT
                SELECT id, training, status
                FROM training_status
                                  ) AS x (id, type, status)
        )

请注意,它使用设置差异运算符EXCEPT,它给出了所有可能用户的行数及其成功的训练组合和当前训练状态的差异。如果所有用户的当前状态都已完成,则差异不应产生任何行。非零结果意味着有些用户没有完成所需的培训。最外面的选择给出了不在未完成培训的用户列表中的用户列表,即完成的用户列表!

在MS SQL服务器中为您的数据执行时,它会给出答案2,他是唯一一位成功完成培训的人。

这是MySQL版本:

SELECT id 
FROM users
WHERE id not in (SELECT x.id 
             FROM (SELECT u.id AS id, t.type AS type, 'S' AS status
                   FROM users u, types t
                   WHERE u.type = t.id 
                   ) x  
             WHERE NOT EXISTS
                    (SELECT ts.id, ts.training, ts.status
                     FROM training_status ts
                     WHERE ts.id = x.id AND 
                           ts.training = x.type AND
                           ts.status = x.status
                     )
            )

+------+
| id   |
+------+
|    2 |
+------+
1 row in set (0.00 sec)