我有这样的观点:
SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset
WHERE  (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')
如果我这样称它,它的工作原理是:
SELECT * FROM FooView
但是,如果我添加一个WHERE子句:
SELECT * FROM FooView WHERE ProcessCode > 0
我收到此错误:
将varchar值'-01-'转换为数据类型int时转换失败.
为什么?由于位置必须采用格式1-2-100-0800-A,因此我不知道如何存在转换错误.是否有可能CAST在WHERE有机会过滤结果之前失败?如果是这样,为什么第一个查询有效?
编辑 - 工作 - 周围
我只是让一位同事建议一个好的解决方案.它有效,但它仍然无法解释为什么最初的问题.
这是在SELECT for ProcessCode中:
CASE WHEN location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_'
THEN CAST(SUBSTRING(location, 9, 4) AS int) ELSE 0 END AS ProcessCode, 
改变你的看法
SELECT location,
       CASE WHEN SUBSTRING(location, 9, 4) > ''
             AND SUBSTRING(location, 9, 4) NOT LIKE '%[^0-9]%' THEN
                 CAST(SUBSTRING(location, 9, 4) AS int) END AS ProcessCode
  FROM dbo.asset
 WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
   AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')
查看此连接项目
SQL Server 可以按照它决定的优化顺序自由地评估 WHERE/SELECT 子句。除非具体化为 INDEXED VIEW,否则视图会扩展到外部查询,因此您的 WHERE 子句实际上正在简化到视图中,即
SELECT * FROM FooView WHERE ProcessCode > 0
 -- is really seen as
SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset
WHERE  (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE'))
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_')
AND CAST(SUBSTRING(location, 9, 4) AS int) > 0 ---- << Expanded inline
由于该表达式同时用于 SELECT 和 WHERE 子句,因此 SQL Server 似乎决定在原始检索中首先解析 SELECT 子句中的表达式。通过使用 Ctrl-L 查看查询执行计划可以轻松看出这一点。您将看到 SQL Server 从表中进行一次检索,同时采用 2 个表达式 beinglocation和。CAST(SUBSTRING(location, 9, 4) AS int)