phpMyAdmin
 sql >> Datenbank >  >> Database Tools >> phpMyAdmin

Wählen Sie einen Datensatz aus, nur wenn der vorherige einen niedrigeren Wert hat, dauert es zu lange und schlägt fehl

Hier ist eine Lösung für Ihre Frage 1, die viel schneller ausgeführt wird, da Sie viele vollständige Tabellenscans und abhängige Unterabfragen haben. Hier haben Sie höchstens einen Tabellenscan (und vielleicht eine temporäre Tabelle, je nachdem, wie groß Ihre Daten sind und wie viel Speicher Sie haben). Ich denke, Sie können es hier leicht an Ihre Frage anpassen. Frage 2 (ich habe es nicht wirklich gelesen) ist wahrscheinlich auch beantwortet, da es jetzt einfach ist, einfach where date_column = whatever hinzuzufügen

select * from (
    select
    t.*,
    if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
    @prev_sn := SerialNumber,
    @prev_toner := Remain_Toner_Black
    from
    Table1 t
    , (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber limit 1) var_init
    order by SerialNumber, id
) sq  
where select_it = 1

BEARBEITEN:

Erklärung:

Mit dieser Zeile

    , (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber 

wir initialisieren einfach die Variablen @prev_toner und @prev_sn im Flug. Es ist dasselbe, als ob man diese Zeile überhaupt nicht in der Abfrage hat, sondern vor die Abfrage schreibt

SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...

Warum also die Abfrage, @prev_sn einen Wert zuzuweisen, und warum nach Seriennummer bestellen? Die Reihenfolge ist sehr wichtig. Ohne order by gibt es keine garantierte Reihenfolge, in der Zeilen zurückgegeben werden. Außerdem werden wir mit Variablen auf den vorherigen Zeilenwert zugreifen, daher ist es wichtig, dass gleiche Seriennummern "zusammen gruppiert" werden.

Die Spalten in der select-Klausel werden nacheinander ausgewertet, daher ist es wichtig, dass Sie zuerst diese Zeile auswählen

if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,

bevor Sie diese beiden Zeilen auswählen

@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black

Warum ist das so? Die letzten beiden Zeilen weisen den Variablen nur die Werte der aktuellen Zeilen zu. Dazu in dieser Zeile

if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,

Die Variablen enthalten immer noch die Werte der vorherigen Zeilen. Und was wir hier tun, ist nichts anderes als zu sagen "wenn der Wert der vorherigen Zeile in der Spalte Remain_Toner_Black kleiner ist als der Wert in der aktuellen Zeile und Die Seriennummer der vorherigen Zeilen ist dieselbe wie die Seriennummer der tatsächlichen Zeilen, geben Sie 1 zurück, andernfalls geben Sie 0 zurück."

Dann können wir in der äußeren Abfrage einfach sagen "wähle jede Zeile aus, in der die obige 1 zurückgegeben hat".

Angesichts Ihrer Abfrage benötigen Sie nicht alle diese Unterabfragen. Sie sind sehr teuer und unnötig. Eigentlich ist es ganz verrückt. In diesem Teil der Abfrage

    SELECT  a.ID, 
            a.Time, 
            a.SerialNumber, 
            a.Remain_Toner_Black,
            a.Remain_Toner_Cyan,
            a.Remain_Toner_Magenta,
            a.Remain_Toner_Yellow,
            (
                SELECT  COUNT(*)
                FROM    Reports c
                WHERE   c.SerialNumber = a.SerialNumber AND
                        c.ID <= a.ID) AS RowNumber
    FROM    Reports a

Sie wählen die gesamte Tabelle aus und für jede Zeile Sie zählen die Zeilen innerhalb dieser Gruppe. Das ist eine abhängige Unterabfrage. Alles nur, um eine Art Zeilennummer zu haben. Dann tun Sie dies ein zweites Mal, nur damit Sie diese beiden temporären Tabellen verbinden können, um die vorherige Zeile zu erhalten. Wirklich, kein Wunder, dass die Leistung schrecklich ist.

Also, wie kann ich meine Lösung an Ihre Frage anpassen? Anstelle der einen Variablen, die ich verwendet habe, um die vorherige Zeile für Remain_Toner_Black zu erhalten, verwenden Sie vier für die Farben Schwarz, Cyan, Magenta und Gelb. Und gesellen Sie sich einfach zum Drucker- und Kundentisch, wie Sie es bereits getan haben. Bestellen bis nicht vergessen und fertig.