Ответ 1
SQL Server 2012 и более поздние версии
Просто используйте Try_Convert
вместо:
TRY_CONVERT принимает переданное ему значение и пытается преобразовать его в указанный тип_данных. Если листинг преуспевает, TRY_CONVERT возвращает значение как указанный тип_данных; если возникает ошибка, возвращается null. Однако, если вы запросите преобразование, которое явно не разрешено, TRY_CONVERT завершится с ошибкой.
SQL Server 2008 и ранее
Традиционным способом обработки этого является защита каждого выражения с помощью case-case, поэтому независимо от того, когда он будет оцениваться, он не создаст ошибку, даже если логически кажется, что оператор CASE не нужен. Что-то вроде этого:
SELECT
Account_Code =
Convert(
bigint, -- only gives up to 18 digits, so use decimal(20, 0) if you must
CASE
WHEN X.Account_Code LIKE '%[^0-9]%' THEN NULL
ELSE X.Account_Code
END
),
A.Descr
FROM dbo.Account A
WHERE
Convert(
bigint,
CASE
WHEN X.Account_Code LIKE '%[^0-9]%' THEN NULL
ELSE X.Account_Code
END
) BETWEEN 503100 AND 503205
Однако мне нравится использовать такие стратегии, как это с SQL Server 2005 и выше:
SELECT
Account_Code = Convert(bigint, X.Account_Code),
A.Descr
FROM
dbo.Account A
OUTER APPLY (
SELECT A.Account_Code WHERE A.Account_Code NOT LIKE '%[^0-9]%'
) X
WHERE
Convert(bigint, X.Account_Code) BETWEEN 503100 AND 503205
Что это значит, стратегически переключать значения Account_Code
на NULL
внутри таблицы X
, если они не являются числовыми. Я изначально использовал CROSS APPLY
, но как Mikael Eriksson, так удачно указав, это привело к той же ошибке, потому что парсер запросов столкнулся с той же проблемой оптимизации моей попытки чтобы заставить порядок выражения (предикат пускал его победил). Переключившись на OUTER APPLY
, он изменил фактическое значение операции, чтобы X.Account_Code
мог содержать NULL
значения во внешнем запросе, что требует правильного порядка оценки.
Вам может быть интересно прочитать Erland Sommarskog запрос Microsoft Connect об этой проблеме с порядковым номером. Он на самом деле называет это ошибкой.
Здесь есть дополнительные проблемы, но я не могу их сейчас решить.
P.S. Сегодня у меня был мозговой штурм. Альтернативой "традиционному способу", который я предложил, является выражение SELECT
с внешней ссылкой, которая также работает в SQL Server 2000. (Я заметил, что с момента обучения CROSS/OUTER APPLY
я улучшил возможности своих запросов со старыми Также версии SQL Server - поскольку я становлюсь более универсальным с возможностями "внешней ссылки" в SELECT
, ON
и WHERE
предложениях!)
SELECT
Account_Code =
Convert(
bigint,
(SELECT A.AccountCode WHERE A.Account_Code NOT LIKE '%[^0-9]%')
),
A.Descr
FROM dbo.Account A
WHERE
Convert(
bigint,
(SELECT A.AccountCode WHERE A.Account_Code NOT LIKE '%[^0-9]%')
) BETWEEN 503100 AND 503205
Это намного короче, чем оператор CASE
.