了解为什么我的CAST到INT无法正常工作

use*_*574 1 t-sql sql-server sql-server-2012

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

现在我知道有些OrderNo值包含“ E”,但是就我而言,我正在CTE中将其过滤掉。如果我自己在CTE中运行该语句,则会得到580条记录,而这些记录中都没有字母。

这里发生了什么?

Aar*_*and 7

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

另外,检查是否存在小数和无az并不是过滤非数字的可靠方法。

我认为,以下两种方法都消除了CTE的需要,因为您只是在使用它来尝试强制执行过滤器。CTE可以合并到其余查询中。也许值得一读的是关于CTE的其他一些花絮

试试TRY_CONVERT()我在这里写过):

WHERE TRY_CONVERT(int, CTE.OrderNo) >= 21187;
Run Code Online (Sandbox Code Playgroud)

如果您使用的旧版本不支持TRY_CONVERT,则可以尝试CASE也许是另一本有用的读物):

WHERE CASE WHEN ISNUMERIC(CTE.OrderNo) = 1 THEN CTE.OrderNo END >= 21187;
Run Code Online (Sandbox Code Playgroud)

但是ISNUMERIC()也不是那么可靠

自从我们知道版本以来,您的查询可以简化为:

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