【问题标题】:Unexpected order running OR operator on SQL Server 2019在 SQL Server 2019 上运行 OR 运算符的意外顺序
【发布时间】:2021-12-29 11:20:11
【问题描述】:

从 SQL Server 2008 R2 迁移到 SQL Server 2019 时遇到问题。 我的代码

DECLARE @str NVARCHAR(50) = 'all',
        @int TINYINT = 1

DECLARE @tmp TABLE (val nvarchar(MAX))
INSERT INTO @tmp VALUES('123')
INSERT INTO @tmp VALUES('all')

SELECT val
FROM @tmp
WHERE @str = 'ALL' OR @int = val

使用 SQL Server 2008 R2 时,没问题。预期的输出如下所示

val
123
all

但是,当我迁移到 SQL Server 2019 时,出现如下错误。此外,它只是在 2019 年不寻常地发生。

消息 245 级别 16 状态 1 第 8 行转换失败时转换 nvarchar 值 'all' 到数据类型 int。

如你所见,第二个条件OR @int = val意外发生了。

我想知道它是否由于与 OR operator 或 case sensitive ALL 与 all 的顺序相关的任何重大更改而失败下一个 SQL Server 2008 R2 版本。


更新

对不起,我的重现代码让你们感到困惑。 This is my original code

【问题讨论】:

  • 错误在这里告诉你问题。在没有收到此错误之前,您似乎只是“幸运”。 'all'显然不是tinyint,但它会在WHERE 中隐式转换为1。 @int 应该是 varchar;您将它与最多可容纳约 10 亿个字符的数据类型进行比较。
  • 不。实际上@tmp 表看起来像[strSplit] this。所以你可以忽略val nvarchar(MAX)。 @Larnu 先生,我只是重现以使我的代码尽可能简单
  • 代码一开始就有缺陷,@NguyễnVănPhong。就像我说的,你以前很幸运。从本质上讲,它是一颗定时炸弹。好吧,非常很幸运,以前在您的生产环境中没有发生这种情况。
  • 我完全同意你们两个我们不应该比较tinyint with nvarchar(max)。我的代码应该是这样的WHERE @str = 'ALL' OR (@str <> 'ALL' AND @int = val),对吧?
  • 嗯,好的。 Here's an answer on this site with good info 和 an article,但您也可以相信,在这里回答您的帮助请求的专家不会对您撒谎。看看,如果你愿意改变你的代码,为什么不直接改变它呢?

标签: sql-server sql-server-2008-r2 sql-server-2019


【解决方案1】:

你应该做以下三件事中的两件事:

(

  1. 要么使用DECLARE @int nvarchar(max) = 1

    或

  2. 使用WHERE val = CONVERT(nvarchar(max), @int)

)

与

  1. 改为使用STRING_SPLIT。即使在本机解决方案存在之前,该循环函数也是您用来拆分字符串的效率最低的方法之一。见https://sqlblog.org/split

这个db<>fiddle 小提琴演示。

而this one 说明了为什么WHERE @str = 'ALL' OR (@str &lt;&gt; 'ALL' AND @int = val) 不是解决方案。您选择的这些模式只有在@str 是始终 'all' 时才有效,因为当它是其他任何东西时它们都会中断。那么为什么有OR呢?


您一直坚持 SQL Server 应该服从从左到右的评估,但我们一直告诉您事实并非如此。

这里是an article by Bart Duncan at Microsoft,他在 SQL Server 上工作,在发布更多 cmets 或进一步编辑您的问题之前,您绝对应该完整阅读。不过,关键点是:

对于

WHERE &lt;expr1&gt; OR &lt;expr2&gt;

之类的事情,您不能依赖表达式评估顺序,因为优化器可能会选择在第一个谓词之前评估第二个谓词的计划。

【讨论】:

  • 谢谢先生。 OR运算符的顺序是否不确定left to right?那么在strSplit ('all', ',')的情况下应该会失败吗?
  • 让我更详细地解释一下。等一下,先生
  • 这里是my original code。你的意思是SQL Server不必遵循你的代码left to right的原则?那么执行计划先运行第二个条件会报错吗?
  • 再一次,如果这段代码唯一可能的工作方式是@str = 'all':dbfiddle.uk/…
  • 我的where子句应该是这样的? WHERE @str = 'all' OR (@str &lt;&gt; 'all' AND @int in (SELECT val FROM dbo.strSplit(@str,',')))
猜你喜欢
  • 1970-01-01
  • 2014-12-26
  • 2019-07-04
  • 2014-05-05
  • 1970-01-01
  • 2015-02-17
  • 2019-10-24
  • 1970-01-01
  • 2022-01-19
相关资源
最近更新 更多