T-SQL All-At-Once 操作解析

Posted johnvwan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了T-SQL All-At-Once 操作解析相关的知识,希望对你有一定的参考价值。

SQL支持一种所谓的同时操作的概念,其含义是认为在同一逻辑查询处理阶段中出现的所有表达式都是同时进行计算的。例如,这个概念就可以解释为什么不能在SELECT子句中引用为同一SELECT子句中的列分配的别名,即使直觉上看起来应该能够这么做。考虑以下查询:

SELECT 
    orderid,
    YEAR(orderdate) AS orderyear, 
    orderyear + 1 AS nextyear 
FROM Sales.Orders; 

以上SELECT列表中第三个表达式对orderyear这一列别名的引用是无效的,即使引用表达式位于这个别名的定义”之后”。因为从逻辑上来说,SELECT列表中各表达式的计算是没有顺序的——它们只是一组表达式。在逻辑上SELECT列表中的所有表达式都
是在同一时刻进行计算的。

再举—个例子:假设你有一个称为T1的表,它有两个整数列:coll 和col2。现在想返回col2/coll大于2的所有行。因为表中一些行的coll列可能等于0,所以需要确保不能对这些列执行除法运算,否则,查询会因为除数为0的错误而失败。为此,有以下查询语句:

SELECT coll, col2 
FROM dbo.Tl 
WHERE col1<> 0 AND col2/col1 > 2; 

这条语句假设SQLServer按从左到右的顺序来计算各表达式,如果表达式col1<>0的结果为FALSE,SQL Server 将会按照“短路求值”的原则,停止计算这个表达式:也就是说,它不会再多此一举地计算表达式col2/col1 > 2, 因为这时已经知道整
个表达式的结果为FALSE。所以可能认为这个查询应该绝不会发生除数为0的错误,然而并不是。

SQL Server确实支待“短路求值”,但因为ANSI SQL中有“同时操作“这么个概念,所以SQL Server可以按它喜欢的任意顺序来自由地处理WHERE子句中的表达式。对于这类问题,SQLServer通常是基于代价估计的标准来做出决定的,也就是说,通常是先计算需要付出较小代价的表达式。可以看到,如果SQLServer决定先处理表达式col2/col1 > 2, 那么该查询可能会因为除数为0的错误而失败。

为了尽可能避免查询执行失败,此处可以采用几种方法。例如,CASE表达式中的 WHEN 子句的计算顺序是有保障的。所以,可以将上面的查询修改如下:

SELECT coll, col2 
FROM dbo.T1
WHERE E
    CASE 
        WHEN col1= 0          THENno    
        WHEN col2/col1 > 2    THENyes 
        ELSEno 
    END =yes; 

如果某个行的col1列等于0,第一个WHEN子句的计算结果就为TRUE,CASE表达式就会返回字符串‘no‘(如果当col1等于0时返回该行,可以将no‘换为‘yes‘)。只有当第一个CASE表达式的计算结果不等千TRUE(即coll不为0),第二个WHEN子句才会检查表达式col2/col1> 2的结果是否为TRUE。如果为TRUE,CASE表达式则返回字符串‘yes‘。对于其他所有情况,CASE表达式将返回字符串‘no‘。只有当CASE表达式的计算结果等于字符串‘yes‘时,WHERE子句中的谓词才会返回TRUE。这样,在表达式中就肯定不会出现除数为0的错误了。

这种解决办法实际上显得很哆嗦,在这个特定的例子中,我们可以使用一种更简单的数学办法来避免除数为0的错误:

SELECT coll, col2 
FROM dbo.Tl 
WHERE coll<> 0 and col2 > 2*col1 ; 

示例代码解释了“同时操作“这一SQL独特而又重要的概念,以及SQLServer 可以确保CASE表达式中WHEN子句的处理顺序这一事实。

 

 

好了,本篇文章就介绍到这儿,欢迎大家留言交流;喜欢或有帮助到您的话,点个赞或推荐支持一下! 



以上是关于T-SQL All-At-Once 操作解析的主要内容,如果未能解决你的问题,请参考以下文章

用SQL语句操作数据------解析

30分钟全面解析-SQL事务+隔离级别+阻塞+死锁

30分钟全面解析-SQL事务+隔离级别+阻塞+死锁

使用 T-SQL 解析 JSON

如何解析从 T-SQL 查询返回的行

T-SQL 以表格格式解析 XML 响应