我有以下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
吗?
答案 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;