SQL无法正确识别和遵守WHERE语句

时间:2013-07-15 20:07:13

标签: sql-server

我有两张桌子。

DECLARE @definitions TABLE
( fDefId varchar(8)   ,
  dType  varchar(MAX) ,
  fName  varchar(MAX)
)

INSERT @definitions values('8c7eab0e','string','custpartno')
INSERT @definitions values('8c7eab02','int'   ,'itemno'    )

DECLARE @fields TABLE
( rowId varchar(8)   ,
  fkFId varchar(8)   ,
  adj   varchar(MAX)
)

INSERT @fields values('83EDE211','8c7eab0e','89319971151801')
INSERT @fields values('83EDE211','8c7eab02','1'             )

我正在尝试查找@fields中值不是int的记录,而@definitions表中的相关记录的dType值为{{ 1}}。

当我尝试获取此结果列表(如果有)时,我尝试了这些语句:

'int'

并且两者都出现了这个错误:

SELECT f.rowId ,
       f.fkFId ,
       f.adj   ,
       d.fName
  FROM @fields      f
  JOIN @definitions d ON  f.fkFId = d.fDefId
                      AND d.dType = 'int'
  WHERE ISNUMERIC( adj        ) <> 1
     OR CAST(      adj AS INT ) <> adj

SELECT *
FROM ( SELECT f.rowId ,
              f.fkFId ,
              f.adj   ,
              d.fName
       FROM @fields      f
       JOIN @definitions d ON  f.fkFId = d.fDefId
                           AND d.dType='int'
     ) a
WHERE ISNUMERIC( adj        ) <> 1
   OR CAST(      adj AS INT ) <> adj

但是,当我第一次将值存储在像这样的表变量中时:

The conversion of the varchar value '89319971151801' overflowed an int column.

我得到了预期的结果(在这个例子中没有记录)。

如果我删除了DECLARE @temp TABLE ( rowId varchar(8), fDefId varchar(8), adjusted varchar(MAX) ) INSERT @temp SELECT f.rowId , f.fkFId , f.adj FROM @fields f JOIN @definitions d ON f.fkFId = d.fDefId AND d.dType = 'int' SELECT * FROM @temp WHERE ISNUMERIC( adjusted ) <> 1 OR CAST( adjusted AS INT ) <> adjusted 条款,我会得到以下结果:

enter image description here

包含大字段的行不存在,那么为什么在添加WHERE后会导致错误?

我也可以通过转换为WHERE而不是BIGINT来避免此问题,但为什么会这样,因为INTJOIN子句删除了不是WHERE从一开始INT

1 个答案:

答案 0 :(得分:1)

您是否知道SQL标准没有强制要求特定的表达式评估顺序或表达式评估的短路的要求?只要保持语义(非意图),查询优化器就可以自由地重新排列整个查询。

你对事物进行了第二次尝试,对datetype = 'int'进行预过滤并加载过滤结果,因为这会强制查询处理器上的操作顺序。

您的单个​​查询尝试失败,因为表达式

CAST( adj AS INT ) <> adj

哪些

  • 需要varchar
  • 将其转换为int
  • int转换回varchar,最后转换为......
  • varchar(包含int的规范化/规范字符串表示形式)与原始varchar值进行比较。

失败。它失败是因为查询处理器必须为每个候选行评估该表达式,无论列datatype是否包含int

第二次单查询尝试与from子句中的派生表失败,因为优化器足够聪明,可以看到查询可以重构,以便不使用派生表。

当然,真正的问题是你有一个非规范化的数据库设计,你正在重载列adj的含义(和数据类型),试图使一个表成为多个事物。 / p>

相关问题