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