2

我有两张桌子。

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值不是 an并且表中int相关记录的值为 的记录。@definitionsdType'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

我得到了预期的结果(本例中没有记录)。

如果我删除该WHERE子句,我会得到以下结果:

在此处输入图像描述

没有大字段的行,那么为什么添加后会导致错误WHERE

我也可以通过转换 asBIGINT而不是来避免这个问题INT,但是为什么这很重要,因为JOINandWHERE子句从一开始就删除了不是 an 的值INT

4

1 回答 1

1

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

您的第二次尝试,预先过滤datetype = 'int'和加载过滤结果是有效的,因为这会强制查询处理器上的操作顺序。

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

CAST( adj AS INT ) <> adj

哪个

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

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

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

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

于 2013-07-15T20:47:33.637 回答