Bei SQL SELECT mehrere ID Werte einer Spalte ausschließen?
Ich habe eine Tabelle, die Nutzer IDs und verschiedene Userdetails (z.B. Email-Adresse etc.) über diesen für ein JAVA Programm festhält.
Das Programm lädt einmalig bei Start alle User herunter (also mit allen IDs). Danach sollen beim aktualisieren nur noch die noch nicht herunter geladenen (fehlenden) Userdaten von anderen Usern geladen werden (falls es neue Nutzer gibt). In Java habe ich die bereits geladenen Nutzer und ihre IDs in einer Liste.
Aber wie schließe ich mehrere ID Werte bei einem SELECT aus? Ich habe jetzt die Bedingung: "SELECT * FROM user_data WHERE ID != " - und jetzt möchte ich z.B. alle IDs außer 0,1,2 oder 3.
5 Antworten
Mehrere Ansätze (zum Teil aber in einigen DBMS nicht verfügbar; daher Standard-SQL)
1. Table-Join
Da du ein Statement absetzt, kannst du einen Table-Join nehmen. (Besser wären SP. = sicherer, schneller, einfacher zu pflegen)
Falls du die Tabellen bearbeiten kannst, ist "flaggen" (bit-flag, timestamp, rowversion, etc.) auch ein gutes Mittel, um noch performanter zu werden.
2. IN & BETWEEN
Der Operator IN gestattet dir nicht zusammenhängende Bereiche zu deklarieren.
Der Operator BETWEEN legt zusammenhängende Bereiche fest, lässt sich aber koppeln, also mit "OR" verlängern, um weitere zusammenhängende Bereiche festzulegen.
Beispiele:
Inklusion
... WHERE id IN (0, 1, 2, 3, 22)
... WHERE id BETWEEN 0 AND 3 OR id = 22
Exklusion (= deine Anforderung)
... WHERE id NOT IN (0, 1, 2, 3, 22)
... WHERE id NOT BETWEEN 0 AND 3 AND id <> 22
-----------------------
Wenn du wählen kannst, nimm Ansatz (1) mit den SP. Er ist sicherer, schneller & pflegeleichter. Und er erzeugt weniger Traffic.
Du kannst das mit Verkettungen lösen:
WHERE id IN (1, ..., x) OR id IN (999, ...., y) OR id IN (9,999, ...., z)
Hello there,
eine zweite Tabelle ist hier nicht nötig.
Wenn es mehrere Werte sein können, machst du es folgendermaßen:
SELECT * FROM user_data
WHERE ID NOT IN(1, 4, 6, 3);
Hast du das Ganze vielleicht dynamisch als Array in PHP, dann kannst du diese Zahlen auch einfügen in das Statement:
$sql = "SELECT * FROM user_data
WHERE ID NOT IN ( " . implode(',', $werte) . ");";
Hoffe ich konnte dir helfen.
MfG
Alex
Nur ums mal Up To Date zu halten. Ich hab nach geguckt und man kann den chache dafür bestimmen . Es geht also , wenn man will , in ganz andere dimensionen ;)
Wenn die jemand braucht, sollte er sein Datenbankdesign überdenken^^
Bei meiner Datenbank (IBM DB2) habe ich bisher noch keine Begrenzung festgestellen können, obwohl ich z.T. sehr große Datenmengen in den Subselect bekomme. Möglicherweise sind die (einstellbaren) Grenzwerte in der Konfiguration so hoch eingestellt.
Wo siehst Du da ein Designproblem? Würde mich interessieren, da ich öfter einen solchen Subselect benutze und auch nicht wüsste, wie man das sonst machen sollte. Ich habe eine sehr komplexe Datenbankanwendung (57 Tabellen). Ich schätze Deine Ratschläge und habe schon öfter gute Tipps Deinen Antworten entnehmen können.
Nein ich meinte, wenn jemand eine WHERE-Bedingung hat mit einem IN oder NOT IN Teil, der 256 Elemente fasst gegen die geprüft werden soll, so wie Rakon eben meint. Das wäre definitiv schlecht designt wenn man solche Vorgehensweise benötigen würde.
Danke für deine netten Worte übrigens *-* Hab ich eigentlich schon ein Kompliment von dir? :P
Und das nennst du sehr komplex? Ich arbeite in einer Softwarefirma im Support, und unsere Anwendung hat derzeit 575 Tabellen. OK die Datenbank hat auch Null Designkonzept, aber trotzdem^^
Generell zur Vermeidung von doppelten Werten im Select:
SELECT DISTINCT <Spalte> FROM <Table>
Zum Ausschluss von Werten die in Tabelle B bereits stehen:
SELECT ID FROM TabelleA WHERE ID NOT IN (SELECT ID FROM TabelleB)
Bei meiner Datenbank (IBM DB2) gibt es keine Begrenzung bei IN, jedenfalls nicht im Bereich um die 100000.
Habe es gerade ausprobiert: mit 132712 hat es noch funktioniert.
Irgendwo gibt es natürlich eine Grenze.
Hallo,
ich weiß nicht, mit welchem DBMS du arbeitest, aber im Wesentlichen sollte sich nachfolgender Hinweis gleichen. Ich würde bei derartigen Angelegenheiten mit Timestamp arbeiten. Vielleicht hilft folgende Seite auf adäquate Lösungen (eine Lösung für gelöschte Objekte müsste auch noch erstellt werden;): https://msdn.microsoft.com/en-us/library/cc305973(v=sql.110).aspx
WHERE ID NOT BETWEEN -1 AND 4
Anmerkung: Der BETWEEN schließt die angegebenen Grenzwerte ein. Beim Bezug auf das Beispiel in der Frage müsste es heißen BETWEEN 0 AND 3. Bei meiner Datenbank ist das jedenfalls so.
Ja mist das Beispiel ist blöd. Es könnte gut sein, dass die Nummern nicht aufeinander folgen. Also ich will 1,4,6,3 ausschließen. Muss ich dann für jede Nummer einzeln prüfen
(Also WHERE ID != 1 AND ID != 4 AND ...)?
Es ginge über eine zweite Tabelle in die zuerst deine bereits abgerufenen IDs reinschreibst.Aber eine bessere, und gängigere Methode wäre es, ein zusätzliches Feld einfügen in dem der Zeitpunkt der letzten Aktualisierung des jeweiligen Datensatzes speicherst (LastChanged). Beim Abrufen der Daten speicherst du den Zeitpunkt des Abrufes. Beim nächsten Abruf fragst nur Datensätze ab die danach aktualisiert wurden. Es empfiehlt sich, den Zeitpunkt in UTC Zeitzone umzuwandeln um Konflikte zwischen Server- und Clientzeit zu vermeiden.
Ah das klingt nach einer echt guten Lösung! Danke, genau das habe ich gesucht! :)
bein IN werden die werte auf eine anzahl begrenzt , es gehen halt nicht sehr viele ich glaub es waren 256