HAVING子句中CoID列无效问题求助:为何CoID不被识别?
为啥你的
CoID别名在HAVING里识别不了? 这个问题我日常帮人排查SQL问题时碰到过好多次,核心原因其实和SQL的执行顺序直接相关:
SQL语句的执行流程是有固定顺序的,大致是这样:
- 先处理
FROM和JOIN,拉取所有关联的基础数据 - 接着用
WHERE过滤掉不需要的行 - 然后按
GROUP BY指定的列分组 - 再执行
SELECT子句(这一步才会生成你定义的别名CoID) - 最后才轮到
HAVING子句过滤分组结果
所以当数据库执行到HAVING的时候,SELECT里的CoID别名还没被创建出来,自然会报错说“找不到这个列”。
另外,你的原始查询还有个容易被忽略的问题:缺少GROUP BY子句。因为你用了max()这类聚合函数,而SELECT里还包含了非聚合列ac.AccountID,按照标准SQL的要求,必须通过GROUP BY ac.AccountID来指定分组依据(少数数据库比如MySQL在宽松模式下可能允许不写,但这不符合规范,也容易导致结果不符合预期)。
两种解决方案任你选
方案1:直接在HAVING里用原始聚合表达式
最直接的办法就是把HAVING里的别名替换成对应的聚合函数,这样数据库就能直接识别:
select ac.AccountID, max(case when c.Name = 'email' then c.Data end) as Email, max(case when c.Name = 'phone' then c.Data end) as Phone, max(a.CompanyID) as CoID from paul_AccountContacts ac left join paul_Contact c on c.ID = ac.ContactID left join paul_Account a on a.ID = ac.AccountID group by ac.AccountID -- 必须加上这行,不然聚合函数会报错 having max(a.CompanyID) in (1506) order by ac.AccountID
方案2:用子查询/CTE包装查询
如果觉得重复写聚合表达式麻烦,可以把整个查询包装成子查询或者CTE,这样外层查询就能直接用CoID别名了,代码也更清晰:
CTE写法(推荐,可读性更高):
WITH AccountDetails AS ( select ac.AccountID, max(case when c.Name = 'email' then c.Data end) as Email, max(case when c.Name = 'phone' then c.Data end) as Phone, max(a.CompanyID) as CoID from paul_AccountContacts ac left join paul_Contact c on c.ID = ac.ContactID left join paul_Account a on a.ID = ac.AccountID group by ac.AccountID ) SELECT * FROM AccountDetails WHERE CoID in (1506) order by AccountID
子查询写法:
SELECT * FROM ( select ac.AccountID, max(case when c.Name = 'email' then c.Data end) as Email, max(case when c.Name = 'phone' then c.Data end) as Phone, max(a.CompanyID) as CoID from paul_AccountContacts ac left join paul_Contact c on c.ID = ac.ContactID left join paul_Account a on a.ID = ac.AccountID group by ac.AccountID ) AS TempTable WHERE CoID in (1506) order by AccountID
这样两种方案都能完美解决你的问题,而且完全符合SQL的执行规范。
内容的提问来源于stack exchange,提问作者Rilcon42
相关产品推荐
相关产品推荐

