Đây là giải pháp cho câu hỏi 1 của bạn sẽ chạy nhanh hơn nhiều, vì bạn có nhiều bảng quét đầy đủ và các truy vấn phụ phụ thuộc. Ở đây, bạn sẽ chỉ có một lần quét bảng (và có thể là một bảng tạm thời, tùy thuộc vào dung lượng dữ liệu của bạn và dung lượng bộ nhớ bạn có). Tôi nghĩ rằng bạn có thể dễ dàng điều chỉnh nó cho câu hỏi của bạn ở đây. Câu hỏi 2 (Tôi chưa đọc thực sự) có lẽ cũng đã được trả lời vì bây giờ thật dễ dàng chỉ cần thêm 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
- xem nó hoạt động trực tiếp trong sqlfiddle
CHỈNH SỬA:
Giải thích:
Với dòng này
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
chúng tôi chỉ khởi tạo các biến @prev_toner
và @prev_sn
một cách nhanh chóng. Nó giống như việc không có dòng này trong truy vấn mà là viết trước truy vấn
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
Vì vậy, tại sao truy vấn gán giá trị cho @prev_sn và tại sao lại sắp xếp theo số sê-ri? Thứ tự của rất quan trọng. Không có đơn đặt hàng bởi không có thứ tự đảm bảo nào trong đó các hàng được trả lại. Ngoài ra, chúng tôi sẽ truy cập giá trị các hàng trước đó bằng các biến, vì vậy điều quan trọng là các số sê-ri giống nhau được "nhóm lại với nhau".
Các cột trong mệnh đề select được đánh giá lần lượt, vì vậy điều quan trọng là bạn phải chọn dòng này trước tiên
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
trước khi bạn chọn hai dòng này
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
Tại sao vậy? Hai dòng cuối cùng chỉ gán giá trị của các hàng hiện tại cho các biến. Vì trong dòng này
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
các biến vẫn giữ giá trị của các hàng trước đó. Và những gì chúng tôi làm ở đây không gì khác ngoài việc nói "nếu giá trị của các hàng trước đó trong cột Remain_Toner_Black nhỏ hơn giá trị trong hàng hiện tại và số sê-ri của các hàng trước đó giống với số sê-ri của hàng thực, trả về 1, nếu không trả về 0. "
Sau đó, chúng ta có thể chỉ cần nói trong truy vấn bên ngoài "chọn mọi hàng, trong đó ở trên trả về 1".
Với truy vấn của bạn, bạn không cần tất cả các truy vấn con này. Chúng rất tốn kém và không cần thiết. Thực ra nó khá điên rồ. Trong phần này của truy vấn
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
bạn chọn toàn bộ bảng và cho mọi hàng bạn đếm các hàng trong nhóm đó. Đó là một truy vấn phụ phụ thuộc. Tất cả chỉ để có một số loại số hàng. Sau đó, bạn làm điều này lần thứ hai, chỉ để bạn có thể nối hai bảng tạm thời đó để lấy hàng trước đó. Thực sự, không có gì ngạc nhiên khi hiệu suất rất kinh khủng.
Vì vậy, làm thế nào để điều chỉnh giải pháp của tôi cho truy vấn của bạn? Thay vì một biến mà tôi đã sử dụng để lấy hàng trước đó cho Remain_Toner_Black, hãy sử dụng bốn cho các màu đen, lục lam, đỏ tươi và vàng. Và chỉ cần tham gia bảng Nhà in và Khách hàng như bạn đã làm. Đừng quên thứ tự trước khi bạn hoàn thành.