别名和聚合函数的 MySQL 查询问题

Posted

技术标签:

【中文标题】别名和聚合函数的 MySQL 查询问题【英文标题】:MySQL Query Problem with Alias and Aggregate Functions 【发布时间】:2011-04-08 01:55:14 【问题描述】:

我有一个麻烦的 mysql 查询如下:

SELECT camera_id, ((avg(low_price) + avg(high_price)) / 2) as avg_price
FROM camera_general, camera_products
WHERE camera_id = ir_camera_id
AND dp_post_dt IS NOT NULL
AND dp_post_dt NOT LIKE '0000%'
AND currently_manufactured = 'Yes'
AND ((no_of_sellers >= 0) OR ((TO_DAYS(CURRENT_DATE) - TO_DAYS(dp_post_dt)) < 120))
AND avg_price < 150 
AND camera_id != 1411
AND camera_id != 9
ORDER BY rand();

这个产生了“'where 子句'中的“未知列'avg_price'”错误。我理解这是因为 WHERE 子句中不允许使用列别名。 (如果我在此过程中有任何错误,请纠正我。)

所以,我像这样调整了查询​​:

SELECT camera_id, ((avg(low_price) + avg(high_price)) / 2) as avg_price
FROM camera_general, camera_products
WHERE camera_id = ir_camera_id
AND dp_post_dt IS NOT NULL
AND dp_post_dt NOT LIKE '0000%'
AND currently_manufactured = 'Yes'
AND ((no_of_sellers >= 0) OR ((TO_DAYS(CURRENT_DATE) - TO_DAYS(dp_post_dt)) < 120))
AND ((avg(low_price) + avg(high_price)) / 2) < 150 
AND camera_id != 1411
AND camera_id != 9
ORDER BY rand();

用实际计算替换别名,此查询产生错误:“无效使用组函数”。我理解这是因为 avg() 直到 WHERE 子句完成处理后才会发生。

然后我尝试了:

SELECT camera_id, ((avg(low_price) + avg(high_price)) / 2) as avg_price
FROM camera_general, camera_products
ORDER BY rand();
HAVING camera_id = ir_camera_id
AND dp_post_dt IS NOT NULL
AND dp_post_dt NOT LIKE '0000%'
AND currently_manufactured = 'Yes'
AND ((no_of_sellers >= 0) OR ((TO_DAYS(CURRENT_DATE) - TO_DAYS(dp_post_dt)) < 120))
AND avg_price < 150 
AND camera_id != 1411
AND camera_id != 9;

将 WHERE 替换为 HAVING 并产生此错误“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以获取在 'HAVING camera_id = ir_camera_id' 附近使用的正确语法”。

在这一点上,我觉得我在黑暗中射击,试图让这个查询工作。有人会指导我正确的方向以使这个查询正常运行吗?

谢谢!

【问题讨论】:

【参考方案1】:
    虽然您可以使用WHERE 指定连接条件,但最好在LEFT[INNER] JOIN 子句中执行。 如果要按非聚合字段过滤,请将过滤器放入WHERE,如果需要按聚合过滤,请将条件移入HAVING

    在同一查询中使用聚合和非聚合时,不要忘记GROUP BY

    SELECT camera_id, ((avg(low_price) + avg(high_price)) / 2) as avg_price FROM camera_general INNER JOIN camera_products ON (camera_id = ir_camera_id) WHERE dp_post_dt IS NOT NULL AND dp_post_dt NOT LIKE '0000%' AND currently_manufactured = 'Yes' AND ((no_of_sellers >= 0) OR ((TO_DAYS(CURRENT_DATE) - TO_DAYS(dp_post_dt)) < 120)) AND camera_id != 1411 AND camera_id != 9 GROUP BY camera_id HAVING avg_price < 150 ORDER BY rand();

【讨论】:

谢谢 - 这工作。我理解(向上看)#2 和#3。但是,我仍然有点模糊,为什么做一个 LEFT[INNER] JOIN 更好? WHERE 中的连接条件是旧语法 (ANSI SQL 1989)。它只支持交叉和内连接(对于外连接,不同的服务器有不同的扩展,例如 TSQL 有*= AND =*)。 JOIN 关键字在 SQL 1992 中引入并支持外连接。使用JOIN 可以使您的查询清晰,并且在指定连接条件时使用它被认为是一种很好的样式。 谢谢。感谢您的解释和帮助!【参考方案2】:

ORDER 子句应该在 HAVING 子句之后。 (除了你在ORDER BY rand() 后面加上一个分号; 然后继续HAVING,这实际上是另一个查询的开始,因为第一个以; 结束)。

【讨论】:

谢谢。分号是重新排列之前所有内容的混合。但是,在 HAVING 之后移动 ORDER 子句确实可以解决一个问题,但迫使我将 HAVING 子句中使用的所有非聚合列添加到 GROUP BY 子句中。

以上是关于别名和聚合函数的 MySQL 查询问题的主要内容,如果未能解决你的问题,请参考以下文章

模糊查询和聚合函数

MySQL 基础 SQL -- DQL 数据查询语言(基础查询(字段别名) where条件查询(比较运算符逻辑运算符) 聚合函数分组查询 排序查询分页查询DQL语句执行顺序)

3.1.3MySQL__数据库基本建表查询,登录,sql语句,建表语句,修改表结构,增删改查,as别名,limit分页,distinct去重,聚合函数,

MySQL 基础 -- SQL(通用语法SQL分类DDL 数据定义语言(含数据类型说明)DML 数据操作语言DQL 数据查询语言(别名去重聚合函数排序分页)DCL 数据控制语言)

MySQL聚合函数

EasyClick 之 MySQL 条件查询之聚合函数