Question

I have the following sql query which has a cross apply with a sub query.

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

It runs fine but If I remove the second expression (,REPLACE([Message], 'Upload End. Total Row:', '') cnt_char) in the select the I get the following error

Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'Upload Start' to data type int.

The where clause in the sub query should be specifically excluding all the rows where Message is "Upload Start" but why am I getting this error. Am I not using the CROSS APPLY properly?

Was it helpful?

Solution

SQL is a descriptive language, not a procedural language. The methods of the cross apply logically explain how the results are generated. They do not specify the execution plan. The query optimizer is free to choose any query plan that generates the correct result set.

You need to look at the execution plans for the two queries. My guess is that they are different in a fundamental way. When dealing with type conversions, you should not depend on where clauses to filter before the conversion. Instead, you should use case. Your outer query should look like:

(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;

OTHER TIPS

SQL Server is free to execute your query in whatever order it pleases. That means it can select all the rows, and only apply the filter later. It's allowed to do so in any way that guarantees the same result.

Unfortunately, that guarantee only involves relational logic, not casting operators.

One way out is a double check:

case when Message like 'Upload End.%' then
    CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT)
else null
end AS row_count
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top