Sql server SQL未正确识别和遵守WHERE语句
我有两张桌子Sql server SQL未正确识别和遵守WHERE语句,sql-server,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 TABL
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' )
我试图在@字段
中查找值不是int
的记录,@定义
表中的相关记录的数据类型
值为'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
但是,当我第一次将值存储在表变量中时,如下所示:
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
DECLARE@temp表
(rowId varchar(8),
fDefId varchar(8),
调整后的varchar(最大值)
)
插入@temp
选择f.rowId,
f、 fkFId,
f、 形容词
来自@fields f
在f.fkFId=d.fDefId上连接@d定义
d.dType='int'
从@temp中选择*
其中为数字(调整)1
或转换(调整为INT)调整
我得到了预期的结果(本例中没有记录)
如果我删除WHERE
子句,我会得到以下结果:
带有大字段的行不存在,那么为什么在添加WHERE
后会导致错误
我还可以通过强制转换为
BIGINT
而不是INT
来避免该问题,但是,既然JOIN
和WHERE
子句从一开始就删除了非INT
的值,那么这又有什么关系呢?您知道SQL标准没有要求强制规定表达式求值的特定顺序或表达式求值的短路?查询优化器可以自由地重新排列几乎整个查询,只要保留语义(而不是意图)
第二个尝试是在datetype='int'
上预过滤并加载过滤结果,因为这会强制查询处理器执行操作顺序
您的单个查询尝试失败,因为表达式
CAST( adj AS INT ) <> adj
CAST(调整为INT)调整
哪个
- 获取一个
varchar
- 将其转换为
int
- 将
转换回int
,最后varchar
- 将
(包含varchar
的规范化/规范化字符串表示形式)与原始int
值进行比较varchar
datatype
是否包含int
第二次单次查询尝试在from
子句中使用派生表失败,因为优化器足够聪明,可以看到查询可以重构,从而不使用派生表
当然,真正的问题是,您有一个非规范化的数据库设计,您正在重载列
adj
的含义(和数据类型),试图将一个表变成多个东西。我一直认为WHERE子句是作为一个整体进行计算的。我不知道它一次只能完成一部分。我们必须使用这种设计来实现我们应用程序这一部分的预期结果。它用于从文本文件导入记录,我们需要跟踪和显示每个字段和值的元信息,并允许来回旋转。我们还简化了向导入过程中添加额外字段的过程。我猜最后一种方法实际上对我来说是最好的,因为它将减少评估它是否为int
时的记录数。这是真的吗?或者在设计限制下有更好的方法吗?这就是我的想法。您可能需要考虑使用一个适当的临时表(<代码> CREATETABLE FIO…<代码>),而不是表变量。如果表变量的大小远远超出“几行”(对于“几行”的某些定义),则表变量往往会出现性能问题。您还可以尝试在临时表上放置一个集群主键,以改进连接。查询处理器不在临时表上使用索引,但聚集索引使索引的B树成为包含表数据页的头。它允许查询优化器在扫描时进行索引搜索。谢谢,我将对此进行研究。因为它是短期的,并且只适用于数据透视表中的一列,所以我不希望table变量有超过1000行(在高端)。平均值可能有100-300行。我不指望这会有多大的不同,但不妨检查一下。
CAST( adj AS INT ) <> adj