17 Stimmen

Wie man Massen-SELECT-Abfragen mit mehreren Paaren im WHERE-Cluase erhält

Sagen wir, ich habe eine Tabelle, email_phone_notes, die so aussieht:

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

Also ist jede Email-/Telefonkombination einzigartig, aber es könnten mehrere E-Mail-Adressen mit verschiedenen Telefonnummern oder umgekehrt vorhanden sein. Dies ist etwas konstruiert, spiegelt aber mein Szenario wider.

Ich möchte eine Abfrage wie diese durchführen:

SELECT * FROM email_phone_notes WHERE email = 'foo@bar.com' AND phone = '555-1212';

Aber ich möchte mehrere Paare auf einmal abfragen, damit ich nicht mehrere SELECT-Abfragen machen muss. Es ist auch wichtig, die Paare zusammen zu behalten, damit ich keine versehentliche Telefon-/E-Mail-Kombination zurückgebe, die nicht angefordert wurde.

Ich könnte etwas wie das Folgende machen, aber für die Möglichkeit von mehreren hundert Werten wird die Abfrage sehr lang sein.

SELECT * FROM email_phone_notes WHERE ( 
  (email='foo@bar.com' && phone='555-1212') || 
  (email='test@test.com' && phone='888-1212') || 
   ...

Gibt es eine elegantere Lösung oder sollte ich dabei bleiben?

33voto

eggyal Punkte 117991

Wenn Sie elegantes SQL wünschen, könnten Sie Zeilenkonstruktoren verwenden:

SELECT * FROM email_phone_notes WHERE (email, phone) IN (
  ('foo@bar.com'  , '555-1212'),
  ('test@test.com', '888-1212')
  -- etc.
);

Dies ist jedoch überhaupt nicht indexfreundlich und würde nicht für eine Tabelle von bedeutender Größe empfohlen. Stattdessen könnten Sie eine Tabelle mit den gewünschten Paaren materialisieren und diese mit Ihrer Tabelle verbinden:

SELECT * FROM email_phone_notes NATURAL JOIN (
  SELECT 'foo@bar.com' AS email, '555-1212' AS phone
UNION ALL
  SELECT 'test@test.com', '888-1212'
-- etc.
) t;

Oder füllen Sie alternativ eine (temporäre) Tabelle im Voraus:

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
  ('foo@bar.com'  , '555-1212'),
  ('test@test.com', '888-1212')
  -- etc.
;

SELECT * FROM email_phone_notes NATURAL JOIN foo;

3voto

AndreKR Punkte 30092

Sie können einen Zeilenkonstruktor wie folgt verwenden:

SELECT *
FROM email_phone_notes
WHERE (email, phone) IN (
  ('foo@bar.com', '555-1212'),
  ('test@test.com', '888-1212')
)

SQLfiddle Beispiel

0voto

yyFred Punkte 500

Zuvor wurden Antworten vor fast 10 Jahren bereitgestellt. Es ist jetzt 2020 und die Antwort scheint sich geändert zu haben.

Kurze Antwort: Verwenden Sie die Zeilenkonstruktor-Syntax - der Optimierer kann (oder auch nicht) einen Index verwenden.

In diesem Beispiel hier kann der Optimierer den Index verwenden, auch wenn der Zeilenkonstruktor den Präfix des Index nicht abdeckt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X