2016-03-28 15 views
2

Ich brauche eine Spalte mit INT Order in MySQL zu lesen und aus der Säule, die niedrigere Zahl erhalten fehle:PHP MySQL kleinste fehlende Zahl in der Spalte findet

+--------+---------+ 
| ID  | Order | 
+--------+---------+ 
| 1  | 1  | 
| 3  | 5  | 
| 4  | 3  | 
| 5  | 4  | 
| 6  | 2  | 
| 7  | 6  | 
| 8  | 11  | 
+--------+---------+ 

Das Ergebnis ich brauche, ist die Zahl 7 als 1 bis 6 existieren und andere fehlende Nummern größer als 7.

$stmtpre = "SELECT Order FROM tabla ORDER BY Order DESC"; 
$data  = $this -> DBMANAGER -> BDquery($stmtpre); 
     $count  = 0; 
     while ($row = mysqli_fetch_assoc($data)){ 
      $count++; 
      if($row['Order']!==$count){ 
       $result= $count; #store first lower get 
       break; 
      } 
     } 
return $result; 
+1

Hinweis helfen, dass, um ein reserviertes Wort ist - und warum nicht die Nummer 0? – Strawberry

+0

danke Bestellung ist ein Beispiel, nur Zahlen> 0. Ich habe eine neue Antwort Dinamic –

Antwort

3

Wenn die Order Spalte indiziert ist, können Sie die erste fehlende Zahl mit SQL bekommen, ohne die komplette Tabelle Lesen eines ohne LEFT mit JOIN:

SELECT t1.`Order` + 1 AS firstMissingOrder 
FROM tabla t1 
LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1 
WHERE t2.`Order` IS NULL 
    AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla) 
ORDER BY t1.`Order` 
LIMIT 1 

oder (vielleicht intuitivere)

SELECT t1.`Order` + 1 AS firstMissingOrder 
FROM tabla t1 
WHERE NOT EXISTS (
    SELECT 1 
    FROM tabla t2 
    WHERE t2.`Order` = t1.`Order` + 1 
) 
    AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla) 
ORDER BY t1.`Order` 
LIMIT 1 

Die zweite Abfrage wird von MySQL in die erste umgewandelt. Sie sind also praktisch gleichwertig.

aktualisieren

Erdbeere erwähnt einen guten Punkt: Die erste fehlende Zahl 1 sein könnte, die in meiner Anfrage nicht abgedeckt ist. Aber ich konnte keine Lösung finden, die beides ist - elegant und schnell.

Wir könnten den umgekehrten Weg gehen und nach einer Lücke nach der ersten Nummer suchen. Müsste aber wieder an den Tisch gehen, um die letzte existierende Nummer vor dieser Lücke zu finden.

MySQL (in meinem Fall MariaDB 10.0.19) ist nicht in der Lage, diese Abfrage richtig zu optimieren. Es dauert ungefähr eine Sekunde in einer indizierten (PK) 1M Zeilentabelle, obwohl die erste fehlende Zahl 9 ist. Ich würde erwarten, dass der Server die Suche nach t1.Order=10 aufhört, aber es scheint nicht so zu sein.

Eine andere Möglichkeit, die schnell ist, aber hässlich aussieht (IMHO), besteht darin, die ursprüngliche Abfrage in einem Subselect nur zu verwenden, wenn Order=1 existiert. Andernfalls geben Sie 1 zurück.

SELECT CASE 
    WHEN NOT EXISTS (SELECT 1 FROM tabla WHERE `Order` = 1) THEN 1 
    ELSE (
     SELECT t1.`Order` + 1 AS firstMissingOrder 
     FROM tabla t1 
     LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1 
     WHERE t2.`Order` IS NULL 
      AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla) 
     ORDER BY t1.`Order` 
     LIMIT 1 
    ) 
END AS firstMissingOrder 

Oder UNION

SELECT 1 AS firstMissingOrder FROM (SELECT 1) dummy WHERE NOT EXISTS (SELECT 1 FROM tabla WHERE `Order` = 1) 
UNION ALL 
SELECT firstMissingOrder FROM (
    SELECT t1.`Order` + 1 AS firstMissingOrder 
    FROM tabla t1 
    LEFT JOIN tabla t2 ON t2.`Order` = t1.`Order` + 1 
    WHERE t2.`Order` IS NULL 
     AND t1.`Order` <> (SELECT MAX(`Order`) FROM tabla) 
    ORDER BY t1.`Order` 
    LIMIT 1 
) sub 
LIMIT 1 
+0

Ich weiß nicht, ob es funktioniert, aber ich wusste, dass es eine Abfrage zu tun haben musste. – AbraCadaver

+0

Testen Sie es, dann werden Sie wissen :-) –

+0

t2 wo bekommen Sie? Es verwendet zwei Tabellen. ?? –

1

könnte der lange Weg um, aber hier ist ein Weg:

while ($row = mysqli_fetch_assoc($data)) { 
    $orders[] = $row['Order']; 
} 

$result = min(array_diff(range(min($orders), max($orders)), $orders)); 
  • einen Bereich von der Mindestbestell auf die maximale Ordnung gefunden gefundene
  • den Unterschied mit den gefundenen Aufträge ermitteln fehlende Aufträge
  • Finden der fehlenden

die niedrigste Auftragsnummer zu bekommen Dies setzt voraus, dass Sie die niedrigsten und höchsten von der Abfrage zurückgegebenen Zahlen als Bereich verwenden möchten. Wenn Sie immer bei 1 starten möchten, verwenden Sie 1 anstelle von min($orders).

Auch als Strawberry weist darauf hin, ist Order ein reserviertes Wort in MySQL so betrachten sie zu ändern oder begrenzen sie mit Back-Zecken SELECT `Order` VON tabla.

0

Von PHP Seite verwenden:

ich arbeite mehr um die Lösung:

Fisrt Funktionsaufruf:

$stmtpre = "SELECT Order FROM tabla ORDER BY Order ASC"; 
$data  = $this -> DBMANAGER -> BDqueryFirstMissingINT($stmtpre, DATABASE); 
echo $data; 

On zweite

function BDqueryFirstMissingINT($stmtpre,$dbUsing){ 
    $data  = $this -> BDquery($stmtpre, $dbUsing); #run the query 
    $count  = 0; 
    while ($row = mysqli_fetch_array($data)){ 
     $count++; 
     $value = (int)$row[0]; 
     if($value!==$count){ 
      $result = $count; 
      break; 
     } 
    } 
    return $result; 
} 

danken, dass Sie

0

Hier ist eine Idee ...

SELECT x.my_order + 1 missing 
    FROM 
    (SELECT my_order FROM my_table 
     UNION 
     SELECT 0 
    ) x 
    LEFT 
    JOIN my_table y 
    ON y.my_order = x.my_order + 1 
WHERE y.my_order IS NULL 
ORDER 
    BY missing 
LIMIT 1; 
+0

Das funktioniert gut. Aber Sie lesen die gesamte Tabelle im Subselect. Es dauert mehr als 2 Sekunden auf meiner 1M Reihentesttabelle. –

+0

@PaulSpiegel Ja, das skaliert nicht allzu gut. – Strawberry

+0

Habe es einfach mit 'UNION ALL' getestet und es" braucht "nur weniger als 0,4 Sekunden. Auf diese Weise wäre es eine gute (lesbare) Lösung für kleinere Tabellen. –

Verwandte Themen