2010-02-11 12 views
8

Mam problem z wysłaniem zapytania do pracy, co moim zdaniem powinno zadziałać. Jest w formiemysql SELECT NOT IN() - zestaw rozłączny?

SELECT DISTINCT a, b, c FROM t1 WHERE NOT IN (SELECT DISTINCT a,b,c FROM t2) AS alias 

Ale mysql dławiki gdzie „IN (” zaczyna. Czy obsługa MySQL to składnia? Jeśli nie, to jak mogę iść o uzyskanie tych wyników? Chcę znaleźć różne krotki (a, b , c) w tabeli 1, których nie ma w tabeli 2.

Odpowiedz

12

Nie powinieneś używać:

SELECT DISTINCT a, b, c FROM t1 WHERE NOT EXISTS (SELECT NULL FROM t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) 

Używanie NOT IN nie jest najlepszą metodą, nawet jeśli zaznaczysz tylko jeden klucz. Powodem jest to, że jeśli użyjesz NOT EXISTS, DBMS będzie musiał tylko sprawdzić indeksy, jeśli istnieją indeksy dla potrzebnych kolumn, gdzie tak jak dla NOT IN będzie musiał odczytać rzeczywiste dane i utworzyć pełny zestaw wyników, który następnie musi zostać sprawdzony .

Używanie LEWEGO DOŁĄCZENIA, a następnie sprawdzanie NULL jest również złym pomysłem, będzie boleśnie powolne, gdy tabele są duże, ponieważ zapytanie musi wykonać całe sprzężenie, odczytanie obu tabel w pełni, a następnie wyrzucenie dużej ilości to. Ponadto, jeśli kolumny pozwalają na wartości NULL, sprawdzenie wartości NULL spowoduje zgłoszenie wyników fałszywie dodatnich.

+0

Wiesz co? Uruchomiłem to zapytanie i trwało to dużo czasu (dłużej niż 10 minut), więc je zabiłem. Następnie ustawiłem tabele tymczasowe dla dwóch tabel i wstawiłem różne informacje. Następnie uruchomiłem kwerendę względem tabel tymczasowych. Zajęło minutę i 4 sekundy. Dlaczego w ten sposób mysql nie mógł zoptymalizować tego zapytania? – user151841

+1

Szczerze mówiąc, mysql jest pod pewnymi względami dość głupi i powolny. Oracle, MS SQL i PostgreSQL radzą sobie znacznie lepiej pod wieloma względami. Oczywiście będzie to o wiele szybsze, jeśli dodasz indeksy do kolumn tabel, jeśli jeszcze ich nie masz. chociaż kosztem czasu włożenia, ponieważ indeksy muszą być aktualizowane za każdym razem, to kwestia tego, ile razy wykonujesz każdą operację i która jest bardziej krytyczna. – wich

0

Z tego co wiem, NOT IN może być używane tylko dla 1 pola na raz, a pole musi być określone pomiędzy "WHERE" i "NOT IN"

(Edycja :) Spróbuj użyć NOT EXISTS.

SELECT a, b, c 
FROM t1 
WHERE NOT EXISTS 
    (SELECT * 
    FROM t2 
    WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c) 

Ponadto, połączenie wewnętrzne na a, b i c jest równe powinno dać ci wszystkie krotki inne niż DISTINCT, podczas gdy LEWE DOŁĄCZENIE z klauzulą ​​WHERE IS NULL powinno dać ci DISTINCT, jak wspomniał Charles.

+0

Święty Boże, która stałaby zapytanie koszmar. Dbam tylko o wartości a, b lub c zależnie od wartości dwóch pozostałych! – user151841

+0

Co powiesz na używanie sprzężenia? Wewnętrzne dołączenie na wszystkich 3 polach powinno zwrócić wszystkie nierozróżnialne krotki. – froadie

+0

Albo jak używać istnieje? SELECT a, b, c FROM t1 GDZIE NIE BEDZIE (WYBIERZ * Z T2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c). Nie jestem pewien, czy to jest dokładnie poprawne, nie miałem dużego doświadczenia z istniejącym – froadie

0

SELECT DISTINCT T1. * FROM t1 LEFT JOIN T2 (t1.a = t2.a I t1.b = t2.b I t1.c = t2.c) GDZIE t2.a IS NULL

+0

Jest to bardzo zły pomysł, jeśli stoły są duże, że lewe łączenie będzie boleśnie powolne. Robisz dużo pracy, czytając do obu tabel w pełni tworząc zestaw wyników łączenia lewostronnego itp., Co jest po prostu niepotrzebne. – wich

+0

Rzeczywiście. Nie pod względem wydajności. – Charles

-1

Konieczność dodania listy kolumn po klauzuli WHERE i REMOVE aliasu.

Testowałem to z podobnym stołem i działa.

SELECT DISTINCT a, b, c 
FROM t1 WHERE (a,b,c) 
NOT IN (SELECT DISTINCT a,b,c FROM t2) 

Korzystanie z mysql world DB:

-- dont include city 1, 2 
SELECT DISTINCT id, name FROM city 
WHERE (id, name) 
NOT IN (SELECT id, name FROM city WHERE ID IN (1,2)) 
+0

Byłoby lepiej użyć NOT EXISTS, NOT IN wymusi zestaw wyników należy dokonać dla zapytania sub czytając całą tabelę, jeśli nie używać nie istnieje zbiór wynikowy musi zostać stworzony dla zapytania sub i jeśli kolumnach są indeksowane, NOT EXISTS odczytują tylko indeksy. – wich

+0

Jesteś tego pewien? Jeśli kolumny nie są zindeksowane, NOT EXISTS jest tak wolny NOT IN. – Yada

0

dobrze, mam zamiar odpowiedzieć na moje własne pytanie, mimo wszystkich rad wielkich inni oddali.

Oto poprawna składnia tego, co próbowałem zrobić.

SELECT DISTINCT a, b, c FROM t1 WHERE (a,b,c) NOT IN (SELECT DISTINCT a,b,c FROM t2) 

Nie mogę ręczyć za skuteczność, ale szersze pytania byłem niejawnie oddanie było „Jak mogę wyrazić tę myśl w SQL”, a nie „Jak uzyskać konkretny zestaw wyników”. Wiem, że to niesprawiedliwe dla wszystkich, którzy zrobili ukłucie, przepraszam!

+1

W zależności od definicji kolumn a, bic t2 może to być błędne! Jeśli pozwalają na wartości NULL, wynik dla NOT IN zawsze będzie nieznany dla każdej takiej wartości. NOT EXISTS * jest * właściwym sposobem na wyrażenie tego, NOT EXISTS został stworzony do tego. – wich

+0

Awesome! Dzięki. – user151841

3

Mam problem z ustaleniem właściwej metody wykonania tego zapytania, nawet z udzielonymi odpowiedziami; Następnie znalazłem MySQL skorowidz mi potrzebne:

SELECT DISTINCT store_type FROM stores WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);

Sztuką musiałem owinąć wokół mój mózg był przy odniesienie do tabeli „sklepów” z pierwszego zapytania wewnątrz podzapytania. Nadzieję, że to pomaga (lub pomaga innym, ponieważ jest to stary wątek.)

Od http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html