[英]SQL: Reuse function result in query without using sub-query
在存储销售订单的MySQL数据库表中,我有一个LastReviewed
列,其中保存了修改销售订单的最后日期和时间(类型timestamp
,默认值CURRENT_TIMESTAMP
)。 我想绘制特定用户在过去90天内每天修改的销售数量。
我正在尝试制作一个SELECT
,该SELECT
返回自LastReviewed
日期以来的天数,以及该范围内有多少条记录。 以下是我的查询,效果很好:
SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND DATEDIFF(CURDATE(),LastReviewed)<=90
GROUP BY days
ORDER BY days ASC
请注意,我为每条记录多次计算DATEDIFF()
和CURDATE()
。 这似乎确实无效,所以我想知道如何重用之前的计算结果。 我尝试的第一件事是:
SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND days<=90
GROUP BY days
ORDER BY days ASC
错误: Unknown column 'days' in 'where clause'
。 于是我开始环顾四周。 基于另一个讨论( 我可以在SELECT查询中重用计算字段吗? ),接下来我尝试了以下方法:
SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND (SELECT days)<=90
GROUP BY days
ORDER BY days ASC
错误: Unknown column 'days' in 'field list'
。 我也尝试了以下方法:
SELECT @days := DATEDIFF(CURDATE(), LastReviewed) AS days,
COUNT(*) AS number FROM sales
WHERE UserID=123 AND @days <=90
GROUP BY days
ORDER BY days ASC
该查询返回零结果,因此,即使我将其放入SELECT
子句并删除WHERE
子句, @days<=90
似乎仍返回false
,我可以看到@days
值低于90的一些结果。
我已经通过使用子查询来使事情工作:
SELECT * FROM (
SELECT DATEDIFF(CURDATE(),LastReviewed) AS sales ,
COUNT(*) AS number FROM sales
WHERE UserID=123
GROUP BY days
) AS t
WHERE days<=90
ORDER BY days ASC
但是我不知道这是否是最有效的方法。 更不用说即使此解决方案为每条记录计算一次CURDATE()
,即使其值从查询开始到结束都相同。 那不是浪费吗? 我在想这个吗? 欢迎提供帮助。
注意:Mod,这应该在CodeReview上吗? 我在这里发布的原因是我尝试使用的代码实际上无法正常工作
您的问题实际上有两个问题。
首先,您忽略了WHERE
在SELECT
之前的事实。 当服务器评估WHERE <expression>
,它便已经知道为评估<expression>
所做的计算的值,并且可以将这些值用于SELECT
。
但是,更糟糕的是,您几乎绝不应该编写将列用作函数参数的查询,因为这通常需要服务器为每一行评估表达式。
相反,您应该使用以下代码:
WHERE LastReviewed < DATE_SUB(CURDATE(), INTERVAL 90 DAY)
优化器将看到这一点并为之兴奋,因为DATE_SUB(CURDATE(), INTERVAL 90 DAY)
可以解析为一个常量,可以在<
比较的一侧使用,这意味着如果存在LastReviewed
为最左侧的相关列,则服务器可以使用索引立即消除LastReviewed >=
该常数值的所有行。
然后DATEDIFF(CURDATE(), LastReviewed) AS days
将仅针对我们已经知道想要的行来评估DATEDIFF(CURDATE(), LastReviewed) AS days
(仍然需要SELECT
)。
在(UserID,LastReviewed)上添加单个索引,服务器将能够非常快速地精确定位相关行。
内置函数比获取行要便宜得多。
使用下面的“ composite”索引,您可以获得更多的性能改进:
INDEX(UserID, LastReviewed)
并更改为
WHERE UserID=123
AND LastReviewed >= CURRENT_DATE() - INTERVAL 90 DAY
您的公式在函数调用中“隐藏” LastRevieded
,使其在索引中不可用。
如果您仍然对该改进不满意,请考虑每晚查询一次,该查询计算昨天的统计信息并将其放在“汇总表”中。 从那里,您提到的SELECT
可以运行得更快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.