我已经问了两个关于这个问题的问题,并且对这两个问题都有很好的答案。
Select a record just if the one before it has a lower value filtered by month
(问题2目前与主题无关,因为我不需要按月过滤)
现在我已经实现了向我建议的代码,只要我的表继续增长sql查询 花了更长的时间。在一开始它需要8秒才能在1000行上执行。 现在在一个超过25,000行的表上,它就失败了。
您可以在此处观看我的查询 - http://sqlfiddle.com/#!2/5c480/1/0
SELECT a.ID, DATE_FORMAT(a.Time,'%d/%m/%y') AS T, a.SerialNumber, p.Model,
b.Remain_Toner_Black BeforeCountBlack,
a.Remain_Toner_Black AfterCountBlack,
b.Remain_Toner_Cyan BeforeCountCyan,
a.Remain_Toner_Cyan AfterCountCyan,
b.Remain_Toner_Magenta BeforeCountMagenta,
a.Remain_Toner_Magenta AfterCountMagenta,
b.Remain_Toner_Yellow BeforeCountYellow,
a.Remain_Toner_Yellow AfterCountYellow
FROM
(
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
) a
LEFT JOIN
(
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 ON a.SerialNumber = b.SerialNumber AND
a.RowNumber = b.RowNumber + 1
INNER JOIN Printers p ON a.SerialNumber = p.SerialNumber
INNER JOIN Customers c ON p.IP = c.IP AND c.Company = 5
WHERE (b.Remain_Toner_Black < a.Remain_Toner_Black AND b.Remain_Toner_Black >= 0) OR (b.Remain_Toner_Cyan < a.Remain_Toner_Cyan AND b.Remain_Toner_Cyan >= 0) OR (b.Remain_Toner_Magenta < a.Remain_Toner_Magenta AND b.Remain_Toner_Magenta >= 0) OR (b.Remain_Toner_Yellow < a.Remain_Toner_Yellow AND b.Remain_Toner_Yellow >= 0)
我需要使用以下3个表格才能选择属于具有ID的特定公司的打印机。
报告:
ID SerialNumber Remain_Toner_Black
29881 Z30PBAHBB00034E 58
30001 Z30PBAHBB00034E 98
30200 Z30PBAHBB00034E 70
30205 BVCfdgdfgdf329F 50
30207 BVCfdgdfgdf329F 40
30210 Z30PBAHBB00034E 50
30301 Z30PBAHBB00034E 100
打印机:
IP SerialNumber Customer
80.179.228.81 Z30PBAHBB00034E 52
客户:
ID IP Company
52 80.179.228.81 5
我的查询完美无缺,并返回:
ID SerialNumber BEFORECOUNTBLACK AFTERCOUNTBLACK
30001 Z30PBAHBB00034E 58 98
30301 Z30PBAHBB00034E 50 100
但是,当我在Reports
表格中的25,000行的桌子上运行它时,它现在失败了。
答案 0 :(得分:3)
这是问题1的解决方案,它运行得更快,因为您有许多全表扫描和从属子查询。在这里,您最多只能进行一次表扫描(也许是一个临时表,具体取决于您的数据有多大以及您有多少内存)。我想你可以在这里轻松调整它。问题2(我还没读过)可能也回答了,因为现在只需添加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
编辑:
说明:
使用此行
, (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber
我们只是动态初始化变量@prev_toner
和@prev_sn
。它与在查询中没有此行但在查询前面写
SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...
那么,为什么查询要为@prev_sn赋值以及为什么按serialnumber排序?订单非常重要。没有订单,没有保证订单返回行。此外,我们将使用变量访问前面的行值,因此将相同的序列号组合在一起并且#34;重要。
select子句中的列是一个接一个地进行评估,因此首先选择此行非常重要
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
在选择这两行之前
@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black
为什么?最后两行仅将当前行的值分配给变量。因此,这一行
if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
变量仍保留前一行的值。我们在这里做的只不过是说&#34;如果列Remain_Toner_Black中的前一行值小于当前行和中的那一行,前一行的序列号与实际相同行序列号,返回1,否则返回0.&#34;
然后我们可以简单地在外部查询中说出&#34;选择每一行,上面返回1&#34;。
根据您的查询,您不需要所有这些子查询。它们非常昂贵且不必要。实际上它太疯狂了。在查询的这一部分
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
您选择整个表格,每行,您可以计算该组中的行数。这是一个从属子查询。所有只是为了得到某种行号。然后你第二次这样做,这样你就可以加入这两个临时表来获取前一行。真的,难怪表演太可怕了。
那么,如何调整我的查询解决方案?而不是我用来获取Remain_Toner_Black的前一行的一个变量,使用四个颜色为黑色,青色,品红色和黄色。只需像您一样加入Printers and Customers表。别忘了订单,你已经完成了。