SQL Server T-SQL CAST仅在IN子句内失败

idfiyjo8  于 2022-12-17  发布在  其他
关注(0)|答案(2)|浏览(125)

我有以下两个表(在SQL Server 2017中):
部件

  • 部件代码INT
  • 激活BIT
  • ...其他字段...

产品

  • 零件代码VARCHAR(6)
  • ...其他字段...

在“产品”表中,PartCode是6位数字或字母后跟5位数字。“部件”表仅涉及具有6位数字部件代码的部件。
此查询成功返回Products表中的数字部件代码列表:

SELECT CAST(PartCode AS INT) FROM Products WHERE ISNUMERIC(PartCode)=1

但是,一旦我将它嵌入到IN中,就像这样:

UPDATE Parts
SET IsActive=0
WHERE PartCode NOT IN (SELECT CAST(PartCode AS INT)
                       FROM Products
                       WHERE ISNUMERIC(PartCode)=1)

它将失败,并显示“将varchar值”K12345“转换为int数据类型时转换失败”。
我知道ISNUMERIC的奇怪行为(它返回1的意外值),但在本例中,SELECT ISNUMERIC('K12345')如预期的那样为0。
既然ISNUMERIC正确地排除了SELECT中的K12345值,为什么它要尝试使用UPDATE强制转换它?它应该从结果集中排除(就像它自己运行SELECT时一样),因此不需要转换。为什么将SELECT放在IN中会使它的行为不同?

dly7yett

dly7yett1#

除了显而易见的“修复数据库”之外,您可以通过使用EXISTS()来避免大多数问题。

UPDATE Parts
   SET IsActive=0
 WHERE NOT EXISTS (
         SELECT *
           FROM Products
          WHERE Products.PartCode = CAST(Parts.PartCode AS VARCHAR(6))
       )

这样你就可以把一个整数转换成一个字符串,而且它总是有效的,它还继续允许使用Products.PartCode上的任何索引。

wljmcqd8

wljmcqd82#

在选择项中打勾:

UPDATE Parts
SET IsActive=0
WHERE PartCode NOT IN (
    SELECT
        CASE
            WHEN ISNUMERIC(PartCode)=1 THEN CAST(PartCode AS INT)
            ELSE -1
        END
    FROM Products)

它在您的版本中爆炸式增长的原因是优化器必须在计算select列表 * 之后 * 应用where子句。

相关问题