Hier is een oplossing voor uw vraag 1 die veel sneller zal werken, aangezien u veel volledige tabelscans en afhankelijke subquery's hebt. Hier heb je hoogstens één tabelscan (en misschien een tijdelijke tabel, afhankelijk van hoe groot je gegevens zijn en hoeveel geheugen je hebt). Ik denk dat je het hier eenvoudig kunt aanpassen aan je vraag. Vraag 2 (ik heb het niet echt gelezen) wordt waarschijnlijk ook beantwoord omdat het nu gemakkelijk is om gewoon where date_column = whatever
toe te voegen
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
- zie het live werken in een sqlfiddle
BEWERKEN:
Uitleg:
Met deze regel
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
we initialiseren gewoon de variabelen @prev_toner
en @prev_sn
op de vlucht. Het is hetzelfde als deze regel helemaal niet in de query hebben, maar voor de query schrijven
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
Dus, waarom de vraag om een waarde toe te kennen aan @prev_sn en waarom bestellen op serienummer? De bestelling op is erg belangrijk. Zonder een bestelling door is er geen gegarandeerde volgorde waarin rijen worden geretourneerd. We zullen ook toegang krijgen tot de waarde van de vorige rijen met variabelen, dus het is belangrijk dat dezelfde serienummers "gegroepeerd" worden.
De kolommen in de select-clausule worden na elkaar geëvalueerd, dus het is belangrijk dat u eerst deze regel selecteert
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
voordat u deze twee regels selecteert
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
Waarom is dat? De laatste twee regels wijzen alleen de waarden van de huidige rijen toe aan de variabelen. Daarom in deze regel
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
de variabelen bevatten nog steeds de waarden van de vorige rijen. En wat we hier doen is niets meer dan zeggen "als de waarde van de vorige rijen in kolom Remain_Toner_Black kleiner is dan die in de huidige rij en het serienummer van de vorige rij is hetzelfde als het eigenlijke serienummer van de rij, retour 1, anders retour 0."
Dan kunnen we gewoon in de buitenste vraag zeggen "selecteer elke rij, waarbij de bovenstaande 1 heeft opgeleverd".
Gezien uw zoekopdracht heeft u niet al deze subquery's nodig. Ze zijn erg duur en onnodig. Eigenlijk is het heel gek. In dit deel van de zoekopdracht
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
je selecteert de hele tafel en voor elke rij je telt de rijen binnen die groep. Dat is een afhankelijke subquery. Allemaal om een soort rijnummer te hebben. Dan doe je dit een tweede keer, zodat je die twee tijdelijke tafels kunt samenvoegen om de vorige rij te krijgen. Echt, geen wonder dat de uitvoering verschrikkelijk is.
Dus, hoe kan ik mijn oplossing aanpassen aan uw vraag? In plaats van de ene variabele die ik gebruikte om de vorige rij voor Remain_Toner_Black te krijgen, gebruik vier voor de kleuren zwart, cyaan, magenta en geel. En sluit u gewoon aan bij de tabel Printers en klanten, zoals u al deed. Vergeet de bestelling niet uiterlijk en je bent klaar.