【问题标题】:Changing the order of the where clause is giving an error更改 where 子句的顺序会出错
【发布时间】:2020-11-04 02:27:13
【问题描述】:

当我尝试更改 SQL where 条件的顺序时,我遇到了错误。

例如:

select *
from dbo.abc
where measure_date <> 'null' and stage = 'xyz'
and measure_place = 'xxx' and fact_code = '123' and std_sis like '%180%'
and cast(measure_date as date) >= '2020/09/01' and cast(measure_date as date) <= '2020/10/13'

在上述查询中,如果我在fact_code 之后保留std_sis,我会得到输出结果,而如果我在查询末尾保留std_sis,例如:

select *
from dbo.abc
where measure_date <> 'null' and stage = 'xyz'
and measure_place = 'xxx' and fact_code = '123'
and cast(measure_date as date) >= '2020/09/01' and cast(measure_date as date) <= '2020/10/13'
and std_sis like '%180%'

我收到如下错误:

消息 241,第 16 级,状态 1,第 1 行
从字符串转换日期和/或时间时转换失败。

【问题讨论】:

  • 因此您必须将measure_date 存储为varchar,而不是将其存储为正确的日期。并且您在该列中有一些无效数据。最好的办法是停止使用 varchar 作为日期。下一个最好的事情是纠正无效的。 hack 解决方案是使用 try_convert 并吞下错误。
  • @DaleK 如何通过更改 where 子句顺序来工作?你有什么想法吗?
  • @PoovizhirajanN 它更改了执行计划,并且 SQL Server 发现自己在应用 where 子句之前正在处理其他数据。它在 SQL Server 中是一个非常常见的问题,它会访问它最终不需要的数据。
  • @AminGheibi 我的意思不是问题中的问题 - 就像一个人必须处理的事情一样 - 特别是如果一个表包含无效数据。
  • 顺便说一下measure_date &lt;&gt; 'null'measure_date IS NOT NULL 不同-除非您明确/字面上将“null”一词放入字段中(这会导致转换错误,因为它应该是一个日期)我想你想使用 IS NOT NULL 版本。您还应该使用通用日期,例如 20200901 而不是 2020/09/01 - 后者在某些设置下可能无法正常工作。

标签: sql sql-server tsql


【解决方案1】:

您看到的行为是由于优化器造成的短路。但是,不能保证。我们永远无法预测 LEFT 表达式将首先被评估,RIGHT 表达式将被评估。

为避免此问题,您可以执行以下几项操作:

  • 修复 measure_date 中的数据问题。只保留日期值

  • 您可以像下面这样更改表达式。

TRY_CAST(measure_date, DATE) >= '2020/09/01' AND TRY_CAST(measure_date, DATE)  <= '2020/10/13'
  • 获取日期值的记录并应用过滤器
select * INTO #abc
from dbo.abc
where measure_date <> 'null' and stage = 'xyz'
and measure_place = 'xxx' and fact_code = '123' and std_sis like '%180%'
and isdate(measure_date) = 1

SELECT * FROM #abc
WHERE  cast(measure_date as date) >= '2020/09/01' and cast(measure_date as date) <= '2020/10/13'

Read more on short-circuiting

【讨论】:

  • AFAIK,您使用子查询的解决方案与原始查询存在相同的问题。查询优化器没有义务先处理子查询,然后再处理外部查询。相反,它将尝试优化整个查询。使用单独的查询,即过滤和写入临时表和处理临时表的第二个查询,排除了查询优化器的“帮助”。请注意,CTE(无递归)也将作为一个大查询而不是单个步骤进行优化。
【解决方案2】:

正如@DaleK 在 cmets 中指出的那样,“问题”是您正在转换存储为字符串的日期并且转换无效。

正如 cmets 中指出的,最好的解决方案是将表列类型更改为 date 并修复所有错误数据。

如果你不能这样做,那么另一个选择是使用TRY_CAST(在 SQL 2012 中引入)函数。如果强制转换操作无效且不抛出错误,则此函数返回 NULL

【讨论】:

    猜你喜欢
    • 2020-06-24
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 2010-10-03
    相关资源
    最近更新 更多