Sql server 其中视图别名导致错误

Sql server 其中视图别名导致错误,sql-server,tsql,Sql Server,Tsql,我有这样的看法: 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]-_') 如果我这样称呼它,它会起作用: S

我有这样的看法:

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格式,我不认为会出现转换错误。在WHERE有机会过滤结果之前,是否可能强制转换失败?如果是这样,那么为什么第一个查询可以工作

编辑-解决方案

我刚让一位同事建议了一个好的解决办法。这是可行的,但仍然不能解释最初的问题

这在“为流程代码选择”中:

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, 

演员阵容在where之前就失败了,是的。事实上,如果我没有弄错的话,在SELECT本身之前,在它查看表并确定location列下的子字符串的形状之后,强制转换就失败了

您似乎对返回的子字符串是什么进行了错误计算,因为如果您说格式确实是1-2-100-0800-a,那么SUBSTRINGstr,9,4应该返回0800,但它返回的是“-1-”,而不是INT

把你的陈述分解成几个小的。我会先查看子字符串的结果


希望这会有所帮助。

这在Sql Server 2008上有效,其他一些时髦的东西正在发生

create view myview
AS
SELECT  CAST(SUBSTRING('1-2-100-0800-A', 9, 4) AS int) as ProcessCode
Where '1-2-100-0800-A' LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_'

GO

SELECT * FROM myview WHERE ProcessCode > 0
这是小提琴>

编辑可以是下面建议的执行顺序,请使用ID优化的in进行尝试

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode
FROM   dbo.asset 
Where id in(
 select id
 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 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子句。除非具体化为索引视图,否则视图将扩展到外部查询,因此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子句,所以SQLServer似乎决定在原始检索中首先解析SELECT子句中的表达式。通过使用Ctrl-L查看查询执行计划,可以很容易地看到这一点。您将看到SQL Server从表中进行一次检索,同时使用2个表达式,即location和CASTSUBSTRINGlocation,9和4作为int。

谢谢,但我不认为我计算错了Substring返回的内容。我认为整个问题在于演员阵容是在WHERE过滤器之前进行的,但我可能错了。如果是这样的话,那么为什么第一个查询可以工作呢?我认为这是可行的,因为您只使用一个好的值进行测试。还有其他坏值应该通过WHERE子句删除。你能举个坏值的例子吗?当然,任何不符合常规表达式的东西:ALM00-00-06,1-5-RMT,1-0-DEV。我使用的每个数据都有效。我现在会看到哪些数据破坏了它-如果是全部或特定的模式,您可以对数据进行子集吗?出于兴趣,请选择哪个版本的sql server?位置是什么列类型?SQL Server 2012。地点是varchar24。谢谢。这有点像我问题中的工作。请参阅我的编辑。虽然它提供了一个可行的替代方案,但它并不能解释最初的行为。我已经添加了一个解释。另外,您的解决方案在某种程度上依赖于数据,因为您不是测试正在转换的位,而是测试列数据的模式。这可以解释这种行为。如果在WHERE有机会筛选坏数据之前评估SELECT,则会导致错误。你是这么说的吗?