2012-11-17 8 views
11

Powiedzmy mam tabeli, email_phone_notes, który wygląda tak:MySQL: Jak większość SELECT wiersze z wielu par w WHERE

+-----------------------+--------------+------+-----+---------+-------+ 
| Field     | Type   | Null | Key | Default | Extra | 
+-----------------------+--------------+------+-----+---------+-------+ 
| email     | varchar  | NO | PRI | NULL |  | 
| phone     | varchar  | NO | PRI | NULL |  | 
| notes     | text   | NO |  | 0  |  | 
+-----------------------+--------------+------+-----+---------+-------+ 

Tak, każda kombinacja e-mail/telefon jest wyjątkowy, ale można mieć kilka adresów e-mail z różnymi numerami telefonów i odwrotnie. Jest to trochę zawiłe, ale odzwierciedla mój scenariusz.

Chciałbym zrobić kwerendę tak:

SELECT * FROM email_phone_notes  WHERE email = '[email protected]' AND phone = '555-1212'; 

Ale chciałbym zrobić wiele par na raz, więc nie muszę dokonać kilku SELECT zapytań. Ważne jest również, aby pary były ze sobą połączone, ponieważ nie chcę zwrócić błędnej kombinacji telefon/e-mail, która nie była wymagana.

Mogłem zrobić coś takiego, ale z powodu możliwości kilkuset wartości zapytanie będzie naprawdę długie.

SELECT * FROM email_phone_notes WHERE ( 
    (email='[email protected]' && phone='555-1212') || 
    (email='[email protected]' && phone='888-1212') || 
    ... 

Czy istnieje bardziej eleganckie rozwiązanie, czy powinienem się z tym uporać? Dzięki!

Odpowiedz

21

Jeśli jesteś po eleganckim SQL, można użyć konstruktorów rząd:

SELECT * FROM email_phone_notes WHERE (email, phone) IN (
    ('[email protected]' , '555-1212'), 
    ('[email protected]', '888-1212') 
    -- etc. 
); 

jednak, że nie jest wcale indeksu z dziećmi i nie być zalecane na stole jakiejkolwiek znaczącej wielkości. Zamiast tego, można zmaterializować tabelę ze swoimi pożądanych par i dołącz że z tabeli:

SELECT * FROM email_phone_notes NATURAL JOIN (
    SELECT '[email protected]' AS email, '555-1212' AS phone 
UNION ALL 
    SELECT '[email protected]', '888-1212' 
-- etc. 
) t; 

Albo wstępnie wypełniać (tymczasowe) tabelę:

CREATE TEMPORARY TABLE foo (PRIMARY KEY (email, phone)) Engine=MEMORY 
    SELECT email, phone FROM email_phone_notes WHERE FALSE 
; 

INSERT INTO foo 
    (email, phone) 
VALUES 
    ('[email protected]' , '555-1212'), 
    ('[email protected]', '888-1212') 
    -- etc. 
; 

SELECT * FROM email_phone_notes NATURAL JOIN foo; 
+2

wow to świetnie SYNTAX! –

1

Można użyć row constructor takiego :

SELECT * 
FROM email_phone_notes 
WHERE (email, phone) IN (
    ('[email protected]', '555-1212'), 
    ('[email protected]', '888-1212') 
) 

SQLfiddle example

+1

Niestety, nie użyjemy tego indeksu. – eggyal

+1

Przeklęcie, MySQL. Oryginalna nie wydaje się ani: http://sqlfiddle.com/#!2/86c1e/2 – AndreKR

+0

Pamiętaj, że indeks nie byłby używany na tym stole, ponieważ jest zbyt mały (mniej niż 10 rekordów). – eggyal