用CROSS APPLY抛出错误的SQL查询

时间:2013-06-18 20:25:37

标签: sql sql-server-2008-r2 cross-apply

我有以下sql查询,它与子查询交叉应用。

SELECT 
    pm.[FileName] 
    ,REPLACE([Message], 'Upload End. Total Row:', '') cnt_char
    ,CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT) AS row_count
FROM 
    dbo.ProductMaster pm
CROSS APPLY 
    (SELECT TOP 30 * 
     FROM dbo.ActivityLog lo 
     WHERE [Message] like 'Upload End%' 
       AND lo.[FileName] = pm.[FileName] 
     ORDER BY ActivityDate DESC) AS s

它运行正常但如果我在选择中删除第二个表达式(,REPLACE([Message], 'Upload End. Total Row:', '') cnt_char)我得到以下错误

  

Msg 245,Level 16,State 1,Line 1
  将varchar值“Upload Start”转换为数据类型int时,转换失败。

子查询中的where子句应该明确排除Message为“Upload Start”的所有行,但为什么会出现此错误。我没有正确使用CROSS APPLY吗?

2 个答案:

答案 0 :(得分:1)

SQL Server可以随意以任何顺序执行您的查询。这意味着它可以选择所有行,并且稍后仅应用过滤器。允许以任何方式保证相同的结果。

不幸的是,这种保证只涉及关系逻辑,而不是铸造运营商。

唯一的出路是双重检查:

case when Message like 'Upload End.%' then
    CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT)
else null
end AS row_count

答案 1 :(得分:1)

SQL是一种描述性语言,而不是过程语言。 cross apply的方法在逻辑上解释了如何生成结果。他们没有指定执行计划。查询优化器可以自由选择生成正确结果集的任何查询计划。

您需要查看两个查询的执行计划。我的猜测是,它们在根本上是不同的。在处理类型转换时,您不应依赖where子句在转换之前过滤。相反,您应该使用case。您的外部查询应如下所示:

(case when [Message] like 'Upload End. Total Row:%'
      then CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT)
      when isnumeric([Message]) = 1
      then cast([Message] as int)
end) as row_count;