sql 语句的执行顺序

本文详细介绍了SQL的语法顺序与执行顺序的区别,并通过具体案例解释了如何避免在WHERE或GROUP BY子句中直接使用SELECT语句中的别名。此外,还提供了关于FROM子句、WHERE子句、GROUP BY与ORDER BY子句以及SELECT子句的优化建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     首先要明白一点就是SQL 的语法顺序和执行顺序是不一致的

SQL的语法顺序:

    select   【distinct】 ....from ....【xxx  join】【on】....where....group by ....having....【union】....order by......

SQL的执行顺序:

   from ....【xxx  join】【on】....where....group by ....avg()、sum()....having....select   【distinct】....order by......


这回你知道where 或group by 直接使用select语句中的别名就会报错了吧,但在某些情况下在group by子句中间接使用别名不会报错

情况一:将表达式都写入group by 子句

select case when ta.call_time = 0 then 0  
    when ta.call_time <= 6 and ta.call_time > 0 then 1  
    when ta.call_time <= 60 and ta.call_time > 6 then 2  
    when ta.call_time <= 3600 and ta.call_time > 60 then 3  
    else 4 end as callt,  
      count(ta.annoyanceid) as counts   
from t_annoyance ta  
group by (case when ta.call_time = 0 then 0  
    when ta.call_time <= 6 and ta.call_time > 0 then 1  
    when ta.call_time <= 60 and ta.call_time > 6 then 2  
    when ta.call_time <= 3600 and ta.call_time > 60 then 3  
    else 4 end);  --group by 后面的就相当于callt;

情况二:将表达式放入子查询里

select t1.callt, count(t2.annoyanceid) as counts
  from (select (case
                 when ta.call_time = 0 then 0
                 when ta.call_time <= 6 and ta.call_time > 0 then 1
                 when ta.call_time <= 60 and ta.call_time > 6 then 2
                 when ta.call_time <= 3600 and ta.call_time > 60 then 3
                 else 4
                end) as callt,
               ta.annoyanceid
          from t_annoyance ta) t1,
       t_annoyance t2
 where t1.annoyanceid = t2.annoyanceid
 group by t1.callt;
/* ----------------------------------------------------------------------------------------------------------------------------------------------------*/

from 子句--执行顺序为从后往前、从右到左
表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后)

oracle 的解析器按照从右到左的顺序处理,FROM 子句中的表名,FROM 子句中写在最后的表(驱动表 driving table)将被最先处理,即最后的表为驱动表,在FROM 子句中包含多个表的情况下,你最好选择记录条数最少的表作为驱动表。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为驱动表, 交叉表是指被其他表所引用的表多表连接时,使用表别名作用于每个列上,以减少解析时间并减少那些由列歧义引起的语法错误.

/* ----------------------------------------------------------------------------------------------------------------------------------------------------*/

where子句--执行顺序为自下而上、从右到左

ORACLE 采用自下而上从右到左的顺序解析Where 子句, 将可以过滤掉大量数据的条件写在where的子句的末尾性能最优

/* ----------------------------------------------------------------------------------------------------------------------------------------------------*/

 group by 和order by 子句执行顺序都为从左到右

select子句--少用*号,尽量取字段名称

ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的,

 使用列名意味着将减少消耗时间。

sql 语句用大写,因为 oracle 总是先解析 sql 语句,把小写的字母转换成大写的再执行


/*having 子句----很耗资源,尽量少用

避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.

如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.
(非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,where 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,

where 也应该比having 快点的,因为它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where 跟having比较了。

在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上后者要慢。
如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,where 的作用时间是在计算之前就完成的,而having 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

在多表联接查询时,on 比where 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where 进行过滤,然后再计算,计算完后再由having 进行过滤。

由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值