MSSQL:IN与硬编码值与IN与SQL查询

时间:2012-10-02 10:45:56

标签: sql sql-server sql-in

我有以下查询:

SELECT c004, mesosafe, CAST(SUBSTRING (c000 ,1 , 5) as int) as sortorder, c001, c000, c002
FROM DE_DATA.dbo.t309
WHERE c001 IS NOT NULL
AND c002 = 1
AND mesocomp = 'EMTD'
AND mesoyear IN (
    SELECT MAX(mesoyear) AS currmesoyear
    FROM DE_DATA.dbo.t001
)
AND CAST(SUBSTRING (c000 ,1 , 5) as int) < 101
ORDER BY c000 ASC;

此查询失败,因为某些c000值无法投放,因为它们看起来像008-而不是00052-。这里要求mesoyear(mesoyear IN ...)。如果我单独查询这个SQL部分,我会得到1344

另一方面,此查询有效:

SELECT c004, mesosafe, CAST(SUBSTRING (c000 ,1 , 5) as int) as sortorder, c001, c000, c002
FROM DE_DATA.dbo.t309
WHERE c001 IS NOT NULL
AND c002 = 1
AND mesocomp = 'EMTD'
AND mesoyear IN (
    '1344'
)
AND CAST(SUBSTRING (c000 ,1 , 5) as int) < 101
ORDER BY c000 ASC;

那么硬编码值和SQL查询之间的区别是什么?

修改

我认为原因是子查询的评估晚于主查询。是真的吗?我能对此做些什么?

2 个答案:

答案 0 :(得分:1)

您正在假定某个执行顺序,因为只有您认为“正确”的某些行将根据CAST操作进行评估。这是一个根本的谬误。 SQL是一种声明性的,面向集合的语言,它不会使任何评估顺序承诺像命令式语言那样。因此,你的整个方法都存在缺陷,你提出了错误的问题。某些查询执行计划可能会起作用,但有些可能会失败,但是当查询选择不同的计划时,那些有效的查询执行计划将随后开始失败。

最终你的问题是数据模型,你必须将这个复合c000字段破解为子字符串并强制转换为int值。使用字符串字段存储字符串,使用数字字段存储数字。就那么简单。你想要实现的目标永远不会发挥作用

另请参阅On SQL Server boolean operator short-circuitT-SQL Functions do not imply a certain order of execution

答案 1 :(得分:0)

通常,MsSql在其父级之前运行子查询。当内部查询找到无法转换为mesoyear的相同类型和大小的第一个值时,您查询可能失败。您是否检查了列t309.mesoyeart001.mesoyear是否具有相同的类型?

然而,在某些情况下MsSql不遵循通常的行为。如果您认为是这种情况,请考虑使用FORCE ORDER查询提示(尽管这种情况最终会再次出现)。

最后但并非最不重要的是,如果CAST运算符不安全,您可以(应该)检查是否可以在发生运行时错误之前转换该值:

-- use
AND (1=1
  AND (ISNUMERIC(SUBSTRING(c000 ,1 , 5) = 1)
  AND (CAST(SUBSTRING (c000 ,1 , 5) as int) < 101)
)
-- instead of
AND CAST(SUBSTRING (c000 ,1 , 5) as int) < 101