我有以下查询:
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查询之间的区别是什么?
修改
我认为原因是子查询的评估晚于主查询。是真的吗?我能对此做些什么?
答案 0 :(得分:1)
您正在假定某个执行顺序,因为只有您认为“正确”的某些行将根据CAST
操作进行评估。这是一个根本的谬误。 SQL是一种声明性的,面向集合的语言,它不会使任何评估顺序承诺像命令式语言那样。因此,你的整个方法都存在缺陷,你提出了错误的问题。某些查询执行计划可能会起作用,但有些可能会失败,但是当查询选择不同的计划时,那些有效的查询执行计划将随后开始失败。
最终你的问题是数据模型,你必须将这个复合c000
字段破解为子字符串并强制转换为int值。使用字符串字段存储字符串,使用数字字段存储数字。就那么简单。你想要实现的目标永远不会发挥作用。
另请参阅On SQL Server boolean operator short-circuit和T-SQL Functions do not imply a certain order of execution。
答案 1 :(得分:0)
通常,MsSql在其父级之前运行子查询。当内部查询找到无法转换为mesoyear
的相同类型和大小的第一个值时,您查询可能失败。您是否检查了列t309.mesoyear
和t001.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