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
- beobachten Sie es live in einem sqlfiddle
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.