Wir haben eine Datenbank mit einer Tabelle, deren Werte aus einem anderen System importiert wurden. Es gibt eine automatische Inkrementierungsspalte und es gibt keine doppelten Werte, aber es fehlen Werte. Beispiel: Ausführen dieser Abfrage:
select count(id) from arrc_vouchers where id between 1 and 100
sollte 100 zurückgeben, aber stattdessen 87. Kann ich eine Abfrage ausführen, die die Werte der fehlenden Zahlen zurückgibt? Beispielsweise können die Datensätze für die ID 1-70 und 83-100 vorhanden sein, es gibt jedoch keine Datensätze mit den IDs 71-82. Ich möchte 71, 72, 73 usw. zurückgeben.
Ist das möglich?
mysql
sql
gaps-and-islands
EmmyS
quelle
quelle
select l.id + 1 as start from sequence as l left outer join sequence as r on l.id + 1 = r.id where r.id is null;
Antworten:
Aktualisieren
ConfexianMJS lieferte eine viel bessere Antwort in Bezug auf die Leistung.
Die (nicht so schnelle wie möglich) Antwort
Hier ist die Version, die für Tabellen beliebiger Größe geeignet ist (nicht nur für 100 Zeilen):
gap_starts_at
- erste ID in der aktuellen Lückegap_ends_at
- letzte ID in der aktuellen Lückequelle
order number
Suche nach Lücken nicht eindeutig ist (in der Tabelle werden die Bestellpositionen gespeichert, sodass sich die Bestellnummer, zu der sie gehören, für jede Zeile wiederholt). 1. Abfrage: 2812 Zeilen im Satz (1 Min. 31,09 Sek.) . Erstellen Sie eine weitere Tabelle, indem Sie unterschiedliche Bestellnummern auswählen. Ihre Anfrage ohne meine Wiederholungen: 1009 Zeilen im Satz (18.04 Sek.)SELECT MIN(id) FROM table
?Dies hat nur funktioniert, um die Lücken in einer Tabelle mit mehr als 80.000 Zeilen zu finden:
Ergebnis:
Beachten Sie, dass die Reihenfolge der Spalten
expected
undgot
kritisch ist.Wenn Sie wissen, dass
YourCol
dies nicht bei 1 beginnt und das keine Rolle spielt, können Sie es ersetzenmit
Neues Ergebnis:
Wenn Sie eine Art Shell-Skriptaufgabe für die fehlenden IDs ausführen müssen, können Sie diese Variante auch verwenden, um direkt einen Ausdruck zu erstellen, über den Sie in bash iterieren können.
Dies erzeugt eine Ausgabe wie diese
Sie können es dann kopieren und in eine for-Schleife in einem Bash-Terminal einfügen, um einen Befehl für jede ID auszuführen
Es ist dasselbe wie oben, nur dass es sowohl lesbar als auch ausführbar ist. Durch Ändern des obigen Befehls "CONCAT" kann die Syntax für andere Programmiersprachen generiert werden. Oder vielleicht sogar SQL.
quelle
CONVERT( YourCol, UNSIGNED )
es bessere Ergebnisse liefert, wenn YourCol noch keine Ganzzahl ist.SELECT MAX(YourCol) FROM YourTable;
SELECT IF((z.got-IF(z.over>0, z.over, 0)-1)>z.expected, CONCAT(z.expected,' thru ',(z.got-IF(z.over>0, z.over, 0)-1)), z.expected) AS missing FROM ( SELECT @rownum:=@rownum+1 AS expected, @target-@missing AS under, (@missing:=@missing+IF(@rownum=YourCol, 0, YourCol-@rownum))-@target AS over, IF(@rownum=YourCol, 0, @rownum:=YourCol) AS got FROM (SELECT @rownum:=0, @missing:=0, @target:=10) AS a JOIN YourTable ORDER BY YourCol ) AS z WHERE z.got!=0 AND z.under>0;
Schnelle und schmutzige Abfrage, die den Trick machen sollte:
Auf diese Weise erhalten Sie eine Tabelle mit der ID, über der IDs fehlen, und der vorhandenen next_id sowie der Anzahl der zwischen ... z
quelle
Wenn Sie eine verwenden
MariaDB
, haben Sie eine schnellere (800%) Option mit der Sequenzspeicher-Engine :quelle
"SELECT MAX(column) FROM table"
das Maximum der Sequenz mithilfe einer Variablen aus dem Ergebnis festgelegt und festgelegt werden, z. B. $ MAX ... die SQL-Anweisung kann dann geschrieben werden."SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
Meine Syntax basiert auf PHPSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
mit MySQL-Variablen verwenden.Erstellen Sie eine temporäre Tabelle mit 100 Zeilen und einer einzelnen Spalte mit den Werten 1-100.
Außen Verbinden Sie diese Tabelle mit Ihrer arrc_vouchers-Tabelle und wählen Sie die einzelnen Spaltenwerte aus, bei denen die arrc_vouchers-ID null ist.
Codierung dieses Blind, sollte aber funktionieren.
quelle
Eine alternative Lösung, die eine Abfrage + einen Code erfordert, der eine Verarbeitung ausführt, wäre:
Beachten Sie, dass die Abfrage keine Unterauswahl enthält, von der wir wissen, dass sie vom MySQL-Planer nicht performant verarbeitet wird.
Dies gibt einen Eintrag pro centralValue (cValue) zurück, der keinen kleineren Wert (lValue) oder größeren Wert (rValue) hat, dh:
Ohne auf weitere Details einzugehen (wir werden sie in den nächsten Absätzen sehen), bedeutet diese Ausgabe Folgendes:
Die Grundidee ist also, eine RECHTS- und eine LINKS-Verknüpfung mit derselben Tabelle durchzuführen, um festzustellen, ob wir benachbarte Werte pro Wert haben (dh wenn der zentrale Wert '3' ist, prüfen wir links auf 3-1 = 2 und links auf 3 + 1 rechts), und wenn eine REIHE einen NULL-Wert bei RECHTS oder LINKS hat, wissen wir, dass es keinen benachbarten Wert gibt.
Die vollständige Rohausgabe meiner Tabelle lautet:
Einige Notizen:
quelle
Wenn es eine Sequenz mit einer Lücke von maximal eins zwischen zwei Zahlen gibt (wie 1,3,5,6), kann folgende Abfrage verwendet werden:
source1
id
quelle
Basierend auf der oben von Lucek gegebenen Antwort können Sie mit dieser gespeicherten Prozedur die Tabellen- und Spaltennamen angeben, die Sie testen möchten, um nicht zusammenhängende Datensätze zu finden. Auf diese Weise können Sie die ursprüngliche Frage beantworten und auch demonstrieren, wie Sie @var zur Darstellung von Tabellen & verwenden können. / oder Spalten in einer gespeicherten Prozedur.
quelle
Ich habe es auf verschiedene Arten versucht und die beste Leistung, die ich gefunden habe, war diese einfache Abfrage:
... eine linke Verknüpfung, um zu überprüfen, ob die nächste ID vorhanden ist, nur wenn die nächste nicht gefunden wird, findet die Unterabfrage die nächste vorhandene ID, um das Ende der Lücke zu finden. Ich habe es getan, weil eine Abfrage mit gleichem (=) eine bessere Leistung hat als ein Operator mit mehr als (>).
Bei Verwendung der SQL-Geige wird die Leistung anderer Abfragen nicht so unterschiedlich angezeigt , aber in einer realen Datenbank führt diese obige Abfrage dreimal schneller als andere.
Das Schema:
Befolgen Sie die folgenden Abfragen, um die Leistung zu vergleichen:
Vielleicht hilft es jemandem und nützlich.
Sie können meine Abfrage mit dieser SQL-Geige sehen und testen :
http://sqlfiddle.com/#!9/6bdca7/1
quelle
Obwohl diese alle zu funktionieren scheinen, kehrt die Ergebnismenge bei 50.000 Datensätzen in sehr langer Zeit zurück.
Ich habe dies verwendet und es wird die Lücke oder die nächste verfügbare (zuletzt verwendete + 1) mit einer viel schnelleren Rückkehr von der Abfrage gefunden.
quelle
Wahrscheinlich nicht relevant, aber ich habe nach so etwas gesucht, um die Lücken in einer Folge von Zahlen aufzulisten, und diesen Beitrag gefunden, der mehrere unterschiedliche Lösungen bietet, je nachdem, was genau Sie suchen. Ich habe nach der ersten verfügbaren Lücke in der Sequenz gesucht (dh nach der nächsten verfügbaren Nummer), und dies scheint gut zu funktionieren.
SELECT MIN (l.number_sequence + 1) als nextavabile von Patienten als l LEFT OUTER JOIN Patienten als r on l.number_sequence + 1 = r.number_sequence WHERE r.number_sequence ist NULL. Mehrere andere dort diskutierte Szenarien und Lösungen ab 2005!
So finden Sie fehlende Werte in einer Sequenz mit SQL
quelle