0

我有以下查询:

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 查询有什么区别呢?

编辑:

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

4

2 回答 2

1

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

最终你的问题是数据模型,事实上你必须将这个复合c000字段分解成子字符串并强制转换以获得 int 值。使用字符串字段存储字符串,使用数字字段存储数字。就那么简单。你试图达到的目标永远不会奏效

另请参见关于 SQL Server 布尔运算符短路T-SQL 函数并不暗示特定的执行顺序

于 2012-10-02T11:01:58.920 回答
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
于 2012-10-02T16:32:42.683 回答