Sql-запрос с ошибкой 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) в выборе, я получаю следующую ошибку

Сообщение 245, уровень 16, состояние 1, строка 1
Ошибка преобразования при преобразовании значения varchar "Начало загрузки" в тип данных int.

Предложение where в подзапросе должно специально исключать все строки, где сообщение «Начало загрузки», но почему я получаю эту ошибку. Я неправильно использую CROSS APPLY?


person Satish    schedule 18.06.2013    source источник


Ответы (2)


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;
person Gordon Linoff    schedule 18.06.2013

SQL Server может выполнять ваш запрос в любом порядке. Это означает, что он может выбрать все строки и применить фильтр только позже. Это разрешено делать любым способом, гарантирующим тот же результат.

К сожалению, эта гарантия включает только реляционную логику, а не операторы приведения типов.

Выход один — перепроверить:

case when Message like 'Upload End.%' then
    CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT)
else null
end AS row_count
person Andomar    schedule 18.06.2013
comment
Ваш ответ такой же, как тот, который я принял, но, поскольку другой объясняет его лучше, он принял это. Я проголосовал за тебя. Спасибо. - person Satish; 19.06.2013