我有两张桌子。
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
条款,我会得到以下结果:
包含大字段的行不存在,那么为什么在添加WHERE
后会导致错误?
我也可以通过转换为WHERE
而不是BIGINT
来避免此问题,但为什么会这样,因为INT
和JOIN
子句删除了不是WHERE
从一开始INT
?
答案 0 :(得分:1)
您是否知道SQL标准没有强制要求特定的表达式评估顺序或表达式评估的短路的要求?只要保持语义(非意图),查询优化器就可以自由地重新排列整个查询。
你对事物进行了第二次尝试,对datetype = 'int'
进行预过滤并加载过滤结果,因为这会强制查询处理器上的操作顺序。
您的单个查询尝试失败,因为表达式
CAST( adj AS INT ) <> adj
哪些
varchar
int
int
转换回varchar
,最后转换为...... varchar
(包含int
的规范化/规范字符串表示形式)与原始varchar
值进行比较。失败。它失败是因为查询处理器必须为每个候选行评估该表达式,无论列datatype
是否包含int
。
第二次单查询尝试与from
子句中的派生表失败,因为优化器足够聪明,可以看到查询可以重构,以便不使用派生表。
当然,真正的问题是你有一个非规范化的数据库设计,你正在重载列adj
的含义(和数据类型),试图使一个表成为多个事物。 / p>