2013-09-26 19 views
5

Rozważmy trzy tabele -MySQL: kwerendy SQL zwraca wiersz tylko wtedy, gdy wszystkie wiersze spełniają warunek

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 

Każdy użytkownik ma typ i rodzaje określa szkoleń, że każdy użytkownik danego typu mają do kompletny.

training_status zawiera status wszystkich szkoleń, które użytkownik wykonał i jego wynik (S, F). Jeśli użytkownik jeszcze nie podejmie szkolenia, nie będzie żadnego rzędu dla tego szkolenia.

Chciałbym dowiedzieć się wszystkich użytkowników, którzy pomyślnie ukończyli wszystkie szkolenia, które muszą podjąć.

Tutaj jest kierunek, który mam na myśli:

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

Oczywiście nie jest to prawda zapytania, ponieważ nawet jeśli użytkownik dokonał jednego z treningów, mamy ten wiersz. W powyższym przykładzie chciałbym uzyskać id = 2, ponieważ ukończył oba treningi tego typu.

+0

odpowiedzi dzięki Piotra: 'SELECT id, SUM (stan jest zerowy lub status nie jest 'S') jako oczekujący od użytkowników przyłączyć rodzajów korzystania (typ) dołączyć training_status korzystania (id, training) grupa według id mając oczekującą = 0; ' –

Odpowiedz

6

Spróbuj

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) 

lub

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 

wyjściowa:

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

Oto SQLFiddle demo

+0

Chciałbym uzyskać użytkownika, który ukończył cały swój trening, a nie tych, którzy tego nie zrobili. Konwertowanie tego zapytania na ... WHERE s.status NIE JEST NULL I s.status = "S" nie działa. –

+0

@ zonked.zonda Niestety nie zwracałem uwagi. Zobacz zaktualizowaną odpowiedź. – peterm

+0

Drugie zapytanie wygląda obiecująco. Dziękuję Peter. Pozwól, że spróbuję, a ja zaktualizuję odpowiedź. –

0

Spróbuj

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

Tabela użytkowników jest naprawdę duża. Założenie całej tabeli i usunięcie kilku rzędów będzie bardzo kosztowne. –

0

Spróbuj

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

To jest to samo, co zapytanie, które wpadłem (patrz pytanie), ale zwraca użytkownika 3. –

0

To powinno działać:

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

Zauważ, że używa go ustawić operator różnicowy OPRÓCZ co daje różnicę wierszy wszystkich możliwych użytkowników i ich sukcesy kombinacje treningowe i aktualny status treningowy. Jeśli obecny stan jest ukończony dla wszystkich użytkowników, różnica nie powinna powodować żadnych wierszy. Wynik niezerowy oznacza, że ​​są użytkownicy, którzy nie ukończyli wymaganego szkolenia. Najbardziej zewnętrzny wybór zawiera listę użytkowników, którzy nie znajdują się na liście użytkowników, którzy nie ukończyli szkolenia, czyli listę użytkowników, którzy ukończyli!

Po wykonaniu w serwerze MS SQL dla danych daje odpowiedź 2, który jako jedyny ukończył szkolenie z powodzeniem.

Oto MySQL Wersja:

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) 
Powiązane problemy