2013-09-26 33 views
5

Hãy xem xét ba bảng -MYSQL: truy vấn SQL để trả về một hàng chỉ khi tất cả các hàng thỏa mãn một điều kiện

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 

Mỗi người dùng có một loại, và các loại xác định đào tạo mà mỗi người dùng của một loại đặc biệt phải hoàn thành.

training_status chứa trạng thái của tất cả các khóa đào tạo mà người dùng đã thực hiện và kết quả của nó (S, F). Người dùng vẫn chưa được đào tạo, sẽ không có bất kỳ hàng nào cho khóa đào tạo đó.

Tôi muốn tìm hiểu tất cả người dùng đã hoàn tất thành công tất cả các khóa đào tạo mà họ phải thực hiện.

Dưới đây là hướng mà tôi đang nghĩ trong:

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

Rõ ràng đây không phải là câu hỏi đúng vì ngay cả khi người dùng đã hoàn thành một trong những huấn luyện, chúng tôi nhận hàng đó. Trong ví dụ trên, tôi muốn lấy id = 2 vì anh ta đã hoàn thành cả hai khóa đào tạo của loại hình này.

+0

trả lời nhờ Peter: 'SELECT id, SUM (tình trạng IS NULL hoặc Status không phải là 'S') như cấp phát từ những người dùng tham gia các loại sử dụng (loại) tham gia training_status sử dụng (id, đào tạo) nhóm theo id đang chờ = 0; ' –

Trả lời

6

Hãy thử

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) 

hoặc

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 

Output:

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

Đây là SQLFiddle bản demo

+0

Tôi muốn có được người dùng đã hoàn thành tất cả các khóa đào tạo của mình, chứ không phải những người không làm. Chuyển đổi truy vấn này thành ... WHERE s.status IS NOT NULL AND s.status = 'S' không hoạt động. –

+0

@ zonked.zonda Xin lỗi đã không chú ý. Xem câu trả lời cập nhật. – peterm

+0

Truy vấn thứ hai có vẻ đầy hứa hẹn. Cảm ơn Peter. Hãy để tôi thử và tôi sẽ cập nhật câu trả lời. –

0

Hãy thử điều này

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

Bảng người dùng thực sự lớn. Bắt toàn bộ bảng và sau đó loại bỏ một vài hàng sẽ rất tốn kém. –

0

Hãy thử điều này

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

Điều này giống như truy vấn mà tôi đã đưa ra (xem câu hỏi) nhưng nó trả về người dùng 3. –

0

này nên làm việc:

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) 
     ) 

Lưu ý rằng nó sử dụng thiết lập điều hành khác biệt TRỪ mang đến cho sự khác biệt của hàng của tất cả người dùng càng tốt và thành công của họ kết hợp đào tạo và tình trạng đào tạo hiện tại. Nếu trạng thái hiện tại hoàn tất cho tất cả người dùng, sự khác biệt sẽ không tạo ra hàng. Kết quả khác không có nghĩa là có những người dùng không hoàn thành đào tạo bắt buộc. Lựa chọn ngoài cùng cung cấp danh sách người dùng không có trong danh sách người dùng không hoàn thành khóa đào tạo, tức là danh sách người dùng đã hoàn thành!

Khi được thực hiện trong máy chủ MS SQL cho dữ liệu của bạn, câu trả lời 2 là người duy nhất hoàn tất đào tạo thành công.

Đây là MySQL Version:

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) 
Các vấn đề liên quan