2013-09-26 37 views
5

考慮三個表 -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,因爲他已經完成了兩種類型的訓練。

+0

回答感謝Peter:'SELECT ID,SUM(狀態爲空或狀態不是 'S')從用戶使用使用(類型)加入training_status連接類型待定(id,training)group by id having pending = 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演示

+0

我想讓完成他所有訓練的用戶,而不是那些沒有完成他的訓練的用戶。將此查詢轉換爲... WHERE s.status不爲NULL並且s.status ='S'不起作用。 –

+0

@ zonked.zonda對不起,沒注意。查看更新的答案。 – peterm

+0

第二個查詢看起來很有前途。謝謝彼得。讓我試試看,我會更新答案。 –

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') 
+0

用戶表非常大。整桌子,然後刪除幾行將是非常昂貴的。 –

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' 
+0

這與我提出的查詢(見問題)相同,但它返回用戶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) 
相關問題