Voici une solution pour votre question 1 qui s'exécutera beaucoup plus rapidement, car vous avez de nombreuses analyses de table complètes et des sous-requêtes dépendantes. Ici, vous n'aurez qu'un seul balayage de table (et peut-être une table temporaire, selon la taille de vos données et la quantité de mémoire dont vous disposez). Je pense que vous pouvez facilement l'adapter à votre question ici. La question 2 (je ne l'ai pas vraiment lue) est probablement également répondue car il est maintenant facile d'ajouter simplement where date_column = whatever
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
- le voir fonctionner en direct dans un sqlfiddle
MODIFIER :
Explication :
Avec cette ligne
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
on initialise juste les variables @prev_toner
et @prev_sn
à la volée. C'est la même chose que de ne pas avoir cette ligne dans la requête mais d'écrire devant la requête
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
Alors, pourquoi faire la requête pour attribuer une valeur à @prev_sn et pourquoi commander par numéro de série ? L'ordre par est très important. Sans ordre par, il n'y a pas d'ordre garanti dans lequel les lignes sont renvoyées. Nous accéderons également à la valeur des lignes précédentes avec des variables, il est donc important que les mêmes numéros de série soient "regroupés".
Les colonnes de la clause select sont évaluées les unes après les autres, il est donc important que vous sélectionniez d'abord cette ligne
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
avant de sélectionner ces deux lignes
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
Pourquoi donc? Les deux dernières lignes affectent uniquement les valeurs des lignes actuelles aux variables. Donc dans cette ligne
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
les variables conservent toujours les valeurs des lignes précédentes. Et ce que nous faisons ici n'est rien de plus que de dire "si la valeur des lignes précédentes dans la colonne Remain_Toner_Black est plus petite que celle de la ligne actuelle et le numéro de série des lignes précédentes est le même que le numéro de série des lignes réelles, renvoie 1, sinon renvoie 0."
Ensuite, nous pouvons simplement dire dans la requête externe "sélectionner chaque ligne, où ce qui précède a renvoyé 1".
Compte tenu de votre requête, vous n'avez pas besoin de toutes ces sous-requêtes. Ils sont très chers et inutiles. En fait c'est assez dingue. Dans cette partie de la requête
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
vous sélectionnez le tableau entier et pour chaque ligne vous comptez les lignes au sein de ce groupe. C'est une sous-requête dépendante. Tout simplement pour avoir une sorte de numéro de ligne. Ensuite, vous faites cela une deuxième fois, juste pour pouvoir joindre ces deux tables temporaires pour obtenir la ligne précédente. Vraiment, pas étonnant que les performances soient horribles.
Alors, comment ajuster ma solution à votre requête ? Au lieu de la seule variable que j'ai utilisée pour obtenir la ligne précédente pour Remain_Toner_Black, utilisez quatre pour les couleurs noir, cyan, magenta et jaune. Et rejoignez simplement la table des imprimeurs et des clients comme vous l'avez déjà fait. N'oubliez pas la commande par et vous avez terminé.