Zde je řešení pro vaši otázku 1, které poběží mnohem rychleji, protože máte mnoho úplných skenů tabulky a závislých poddotazů. Zde budete mít nanejvýš jen jeden sken tabulky (a možná i dočasnou tabulku, v závislosti na tom, jak velká jsou vaše data a kolik máte paměti). Myslím, že to zde můžete snadno přizpůsobit své otázce. Otázka 2 (opravdu jsem ji nečetla) je pravděpodobně také zodpovězena, protože je nyní snadné pouze přidat 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
- vidět, jak to funguje živě v sqlfiddle
EDIT:
Vysvětlení:
S tímto řádkem
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
pouze inicializujeme proměnné @prev_toner
a @prev_sn
za běhu. Je to stejné, jako když tento řádek v dotazu vůbec nemáte, ale píšete před dotaz
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
Proč tedy dotaz přiřadit hodnotu @prev_sn a proč objednávat podle sériového čísla? Pořadí podle je velmi důležité. Bez objednávky není zaručeno pořadí, ve kterém jsou řádky vráceny. Také budeme přistupovat k hodnotám předchozích řádků s proměnnými, takže je důležité, aby stejná sériová čísla byla „seskupena“.
Sloupce v klauzuli select se vyhodnocují jeden po druhém, takže je důležité, abyste nejprve vybrali tento řádek
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
než vyberete tyto dva řádky
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
proč tomu tak je? Poslední dva řádky přiřadí proměnným pouze hodnoty aktuálních řádků. Proto v tomto řádku
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
proměnné si stále uchovávají hodnoty z předchozích řádků. A to, co zde děláme, není nic jiného než říkat:„Pokud je hodnota předchozích řádků ve sloupci Remain_Toner_Black menší než hodnota v aktuálním řádku a sériové číslo předchozích řádků je stejné jako skutečné sériové číslo řádků, vrátí 1, jinak vrátí 0."
Pak můžeme jednoduše říci ve vnějším dotazu "vyberte každý řádek, kde výše uvedené vrátilo 1".
Vzhledem k vašemu dotazu nepotřebujete všechny tyto dílčí dotazy. Jsou velmi drahé a zbytečné. Vlastně je to docela šílené. V této části dotazu
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
vyberete celou tabulku a pro každý řádek spočítáte řádky v této skupině. To je závislý poddotaz. Všechno jen proto, abychom měli nějaké číslo řádku. Pak to uděláte podruhé, abyste mohli spojit tyto dvě dočasné tabulky a získat předchozí řádek. Opravdu není divu, že výkon je hrozný.
Jak tedy přizpůsobit své řešení vašemu dotazu? Místo jedné proměnné, kterou jsem použil k získání předchozího řádku pro Remain_Toner_Black, použijte čtyři pro barvy černá, azurová, purpurová a žlutá. A stačí se připojit ke stolu Tiskaři a zákazníci jako vy. Nezapomeňte na objednávku a máte hotovo.