• 【MySQL】为什么在having子句中可以使用在select子句中定义的别名?


    问题描述

    最近在做一道SQL题目的时候,突然产生了一个这样的疑问:

    1. 按照SQL执行顺序的话,应该是这样执行的:
    from
    join
    on
    where
    group by
    having
    select
    distinct
    order by
    limit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. 基于第一条,那么order by可以使用select中定义的别名,这个是合理的。
    2. 但是在实践中发现,如下边的那条SQL语句,having子句也可以使用select中定义的别名refund_rate ,按道理来讲,执行引擎执行到having时应该报找不到refund_rate的定义,这让我感觉有点想不通。
    select 
        product_id,
        round(sum(if_click) / count(product_id), 3) ctr,
        round(IF(sum(if_click) = 0, 0, sum(if_cart) / sum(if_click)), 3) cart_rate,
        round(IF(sum(if_cart) = 0, 0, sum(if_payment) / sum(if_cart)), 3) payment_rate,
        round(IF(sum(if_payment) = 0, 0, sum(if_refund) / sum(if_payment)), 3) refund_rate
    from
        tb_user_event
    where
        year(event_time) = 2021 and month(event_time) = 10
    group by
        product_id
    having 
        refund_rate <= 0.5
    order by
        product_id
    ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    问题解决

    通常这种问题的解决,不外乎两种渠道:

    1. StackOverflow等论坛
    2. MySQL官网

    渠道一:StackOverflow论坛

    通过搜索之后,发现也有跟我一样有此疑惑的老外:

    问题链接:https://stackoverflow.com/questions/49888360/using-alias-in-the-where-and-having-statements

    Only MySQL permits alises in HAVING, it is not standard SQL (see here: https://dba.stackexchange.com/questions/50391/why-does-mysql-allow-having-to-use-select-aliases ) please note that no other major RDBMS allows the use of aliases in WHERE or HAVING.
    只有MySQL数据库运行在having子句中用别名,这里并没有按照标准的SQL

    换句话说,标准的SQL标准是不允许在having中使用select子句中的别名,但是MySQL对这个地方进行了扩展

    渠道二:MySQL8.0官网

    链接: https://dev.mysql.com/doc/refman/8.0/en/problems-with-alias.html

    An alias can be used in a query select list to give a column a different name. You can use the alias in GROUP BY, ORDER BY, or HAVING clauses to refer to the column:

    官网中明确表示

    1. 可以在group byorder byhaving子句中使用别名。**
    2. 不可以在where中使用别名。

    这是因为可能会出现列值还未确定的情况:
    SELECT id, COUNT(*) AS cnt FROM tbl_name WHERE cnt > 0 GROUP BY id;

    另外,MySQL8.0官网的这篇文章也详细说明了这一部分。

    补充:

    在MySQL5.7中,可以对sql_mode属性添加ONLY_FULL_GROUP_BY值来禁止此扩展。在MySQL8.0中此方法无效。

    若禁用了之后,类似的语句在执行的过程中就会报错:
    Non-grouping field 'XXXXX' is used in HAVING clause: ...........
    测试链接:http://sqlfiddle.com/#!9/98dbf7/1

    总结

    以后在MySQL中,可以大胆的用:

    1. 可以在group byorder byhaving子句中使用别名。**
    2. 不可以在where中使用别名。

    其他数据库不一定支持此操作。

    参考

    • https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
    • https://dba.stackexchange.com/questions/50391/why-does-mysql-allow-having-to-use-select-aliases
    • https://dev.mysql.com/doc/relnotes/mysql/8.0/en/
    • https://stackoverflow.com/questions/49888360/using-alias-in-the-where-and-having-statements
  • 相关阅读:
    浅谈One API
    高并发应用实践——限流手段
    新接手一个业务系统,我是这么熟悉的
    火爆全网的头戴式耳机,Y2K辣妹时髦单品——Umelody轻律 U1头戴式耳机!
    C++ 数据类型学习资料
    docker安装(Elasticsearch、kibana、IK分词器)8.4.3
    Python爬虫:某书平台的Authorization参数js逆向
    xcode项目添加README.md文件并进行编辑
    axios 拦截器实现原理
    vue3解决报错:ResizeObserver loop completed with undelivered notifications
  • 原文地址:https://blog.csdn.net/m0_38072683/article/details/133748265