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

Selecteer een record alleen als het record ervoor een lagere waarde heeft, duurt te lang en mislukt

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

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.




  1. Hoe verwijder ik lege rijen in Mysql?

  2. sql verwijder rij fout

  3. phpmyadmin-fout #1062 - Dubbele invoer '1' voor sleutel 1

  4. Tabel maken door structuur van bestaande tabel te kopiëren