Inilah solusi untuk pertanyaan Anda 1 yang akan berjalan lebih cepat, karena Anda memiliki banyak pemindaian tabel lengkap dan subkueri dependen. Di sini Anda paling banyak hanya memiliki satu pemindaian tabel (dan mungkin tabel sementara, tergantung seberapa besar data Anda dan berapa banyak memori yang Anda miliki). Saya pikir Anda dapat dengan mudah menyesuaikannya dengan pertanyaan Anda di sini. Pertanyaan 2 (saya belum benar-benar membacanya) mungkin juga dijawab karena sekarang mudah untuk menambahkan 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
- lihat itu bekerja langsung di sqlfiddle
EDIT:
Penjelasan:
Dengan baris ini
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
kita hanya menginisialisasi variabel @prev_toner
dan @prev_sn
dengan cepat. Ini sama dengan tidak memiliki baris ini sama sekali tetapi menulis di depan kueri
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
Jadi, mengapa kueri menetapkan nilai ke @prev_sn dan mengapa memesan berdasarkan nomor seri? Urutan oleh sangat penting. Tanpa pesanan oleh, tidak ada pesanan yang dijamin di mana baris dikembalikan. Kami juga akan mengakses nilai baris sebelumnya dengan variabel, jadi penting bahwa nomor seri yang sama "dikelompokkan bersama".
Kolom dalam klausa pilih dievaluasi satu demi satu, jadi penting bagi Anda untuk memilih baris ini terlebih dahulu
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
sebelum Anda memilih dua baris ini
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
Mengapa demikian? Dua baris terakhir hanya menetapkan nilai dari baris saat ini ke variabel. Oleh karena itu di baris ini
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
variabel masih memegang nilai dari baris sebelumnya. Dan apa yang kami lakukan di sini tidak lebih dari mengatakan "jika nilai baris sebelumnya di kolom Remain_Toner_Black lebih kecil dari yang ada di baris saat ini dan nomor seri baris sebelumnya sama dengan nomor seri baris yang sebenarnya, kembalikan 1, jika tidak kembalikan 0."
Kemudian kita cukup mengatakan di kueri luar "pilih setiap baris, di mana yang di atas mengembalikan 1".
Mengingat kueri Anda, Anda tidak memerlukan semua subkueri ini. Mereka sangat mahal dan tidak perlu. Sebenarnya itu cukup gila. Di bagian kueri ini
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
Anda memilih seluruh tabel dan untuk setiap baris Anda menghitung baris dalam grup itu. Itu adalah subquery yang bergantung. Semua hanya untuk memiliki semacam nomor baris. Kemudian Anda melakukan ini untuk kedua kalinya, supaya Anda dapat menggabungkan dua tabel sementara itu untuk mendapatkan baris sebelumnya. Sungguh, tidak heran penampilannya mengerikan.
Jadi, bagaimana cara menyesuaikan solusi saya dengan permintaan Anda? Alih-alih satu variabel yang saya gunakan untuk mendapatkan baris sebelumnya untuk Remain_Toner_Black gunakan empat untuk warna hitam, cyan, magenta dan kuning. Dan bergabung saja dengan tabel Printers and Customers seperti yang sudah Anda lakukan. Jangan lupa order dan selesai.