4

我以为我理解了如何SELECT从另一个SELECT语句的结果中做一个,但似乎有某种我不理解的范围模糊。我正在使用 SQL Server 2008R2。

用一个例子来解释是最容易的。

创建具有单个 nvarchar 列的表 - 使用单个文本值和几个数字加载表:

CREATE TABLE #temptable( a nvarchar(30) ); 
INSERT INTO #temptable( a )
    VALUES('apple');
INSERT INTO #temptable( a )
    VALUES(1);
INSERT INTO #temptable( a )
    VALUES(2);

select * from #temptable;

这将返回: apple, 1, 2

用于IsNumeric仅获取可以转换为数字的表格行 - 这将留下文本值apple。这工作正常。

    select cast(a as int) as NumA
    from #temptable 
    where IsNumeric(a) = 1 ;

这将返回:1, 2

但是,如果我使用与内部选择完全相同的查询,并尝试执行数字WHERE子句,它会失败说 cannot convert nvarcharvalue 'apple' to data type int。它是如何恢复价值“苹果”的?

    select 
        x.NumA
    from 
    (
        select cast(a as int) as NumA
        from #temptable 
        where IsNumeric(a) = 1 
    ) x
    where x.NumA > 1
    ;

请注意,如果没有该WHERE子句,失败的查询也可以正常工作:

    select 
        x.NumA
    from 
    (
        select cast(a as int) as NumA
        from #temptable 
        where IsNumeric(a) = 1 
    ) x
    ;

我觉得这非常令人惊讶。我没有得到什么?TIA

4

3 回答 3

0

你得到这个的原因是公平和简单的。执行查询时,会遵循一些步骤。这是一个解析、代数、优化和编译。在这种情况下,algebrize 部分将获取此查询所需的所有对象。优化将使用这些对象来创建将被编译和执行的最佳查询计划......

因此,当您查看该部分时,您会看到它将对#temptable 进行表扫描。#temptable 被定义为您创建表的方式。您将对其进行一些计算是另一回事.....该列仍然具有 nvarchar 数据类型..

要知道这是如何工作的,您必须知道如何阅读查询。首先检索所有对象(从表,内部连接表),然后是谓词(where,on),然后是分组等,然后是选择列(使用强制转换),然后是 orderby。

因此,考虑到这一点,当您有选择的组合时,优化器仍会以这种方式处理它。由于您的选择从属于查询的 from 和 join 部分,这将是出现此错误的原因。

我希望我说清楚一点?

于 2012-10-02T13:46:02.053 回答
0

优化器可以在查询计划中自由移动表达式,以便生成最具成本效益的数据检索计划(不保证谓词的评估顺序)。我认为使用像下面这样的 case 表达式会在没有 ELSE 子句的情况下产生 NULL 并因此将 APPLE 取出

select a from #temptable where case when isumeric(a) = 1 then a end > 1

于 2014-07-09T13:28:03.950 回答
0

如果您查看估计的执行计划,您会发现它已将内部查询优化为外部查询并组合了WHERE子句。

使用 CTE 隔离操作工作(在 SQL Server 2008 R2 中):

declare @temptable as table ( a nvarchar(30) );  
INSERT INTO @temptable( a ) 
    VALUES ('apple'), ('1'), ('2'); 

with Numbers as (    
  select cast(a as int) as NumA 
    from @temptable  
      where IsNumeric(a) = 1  
  )
  select * from Numbers
于 2012-09-18T15:15:33.800 回答