【问题标题】:Understanding why my CAST to INT is not working了解为什么我的 CAST to INT 不起作用
【发布时间】:2020-01-03 22:45:18
【问题描述】:

我尝试运行一个非常简单的代码,但由于我不明白的原因,它无法正常工作。这是我的代码:

WITH CTE AS
(
    SELECT DISTINCT OrderNo
    FROM OrderDet
    WHERE PartNo LIKE '%.%'
      AND OrderNo NOT LIKE '%[a-z]%'
)
SELECT * 
FROM CTE
WHERE CAST(CTE.OrderNo AS INT) >= 21187

运行此代码会引发以下错误:

将 varchar 值“20361E”转换为数据类型 int 时转换失败。

现在我知道有 OrderNo 值包含“E”,但是,就我而言,我在 CTE 中将它们过滤掉。如果我在 CTE 中单独运行语句,我会得到 580 条记录,其中没有一条有任何字母。

这是怎么回事?

【问题讨论】:

  • 欢迎来到 SQL 优化的辉煌世界。无法保证条件的实际评估顺序与您认为的逻辑评估顺序相匹配。
  • 更好的问题是为什么您将字母数字值存储为 OrderNo,然后尝试将其视为数字值。
  • This 回答可能会提供一些线索。
  • 您使用的是哪个版本的 SQL Server?如果它没有不受支持(或非常接近),它应该有 TRY_CONVERT 在它无法转换时产生空值而不是错误。
  • SQL 2012 是的,我实际上知道 TRY_CAST,它绝对有效。但是,我觉得使用它就像一个创可贴,而我的原始查询应该 100% 有效,我只是在寻找原因的解释。看起来很奇怪,它没有按我的意愿工作

标签: sql-server tsql sql-server-2012


【解决方案1】:

如 cmets 中所述,您无法真正控制是否在过滤器之前尝试 CAST;这完全取决于 SQL Server 选择如何优化查询。

此外,检查是否存在小数且没有 a-z 并不是过滤掉非数字的非常可靠的方法。

我认为,以下两种方法都不需要 CTE,因为您只是使用它来尝试强制过滤器首先发生。 CTE 可以折叠到查询的其余部分中; perhaps worth a read are some other tidbits about CTEs.

试试TRY_CONVERT()(其中I wrote about here):

WHERE TRY_CONVERT(int, CTE.OrderNo) >= 21187;

如果您使用的是不支持TRY_CONVERT的旧版本,您可以尝试CASEperhaps another useful read):

WHERE CASE WHEN ISNUMERIC(CTE.OrderNo) = 1 THEN CTE.OrderNo END >= 21187;

但是ISNUMERIC() is not all that reliable either

由于现在我们知道版本,您的查询可以简化为:

SELECT DISTINCT OrderNo
  FROM dbo.OrderDet
  WHERE PartNo LIKE '%.%'
    AND TRY_CONVERT(int, OrderNo) >= 21187;

【讨论】:

  • 谢谢,我不知道您无法真正控制是否在过滤器之前尝试 CAST。我认为 100% CTE 将首先执行,第二个查询将在 CTE 记录上独占执行。有点让我大吃一惊,事实并非如此
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多