Содержание
- @@ERROR (Transact-SQL)
- Синтаксис
- Типы возвращаемых данных
- Примечания
- Примеры
- A. Использование функции @@ERROR для обнаружения конкретной ошибки
- Б. Использование функции @@ERROR для выхода из процедуры по условию
- В. Использование функции @@ERROR с @@ROWCOUNT
- ERROR_MESSAGE (Transact-SQL)
- Синтаксис
- Типы возвращаемых данных
- Возвращаемое значение
- Remarks
- Примеры
- A. Использование функции ERROR_MESSAGE в блоке CATCH
- Б. Использование функции ERROR_MESSAGE в блоке CATCH с другими средствами обработки ошибок
- ERROR_MESSAGE (Transact-SQL)
- Syntax
- Return Types
- Return Value
- Remarks
- Examples
- A. Using ERROR_MESSAGE in a CATCH block
- B. Using ERROR_MESSAGE in a CATCH block with other error-handling tools
- [Перевод] Обработка ошибок и транзакций в SQL Server. Часть 1. Обработка ошибок – быстрый старт
- 1. Введение
- 1.1 Зачем нужна обработка ошибок?
- 2. Основные команды
- 2.1 TRY-CATCH
- 2.2 SET XACT_ABORT ON
- 3. Основной пример обработки ошибок
- 4. Три способа генерации ошибки
- 4.1 Использование error_handler_sp
- 4.2. Использование ;THROW
- 4.3. Использование SqlEventLog
- 5. Финальные замечания
- Триггеры
- Клиентский код
- 6. Конец первой части
@@ERROR (Transact-SQL)
Область применения: SQL Server (все поддерживаемые версии) База данных SQL Azure Управляемый экземпляр SQL Azure Azure Synapse Analytics Analytics Platform System (PDW)
Возвращает номер ошибки для последней выполненной инструкции Transact-SQL.
Соглашения о синтаксисе Transact-SQL
Синтаксис
Ссылки на описание синтаксиса Transact-SQL для SQL Server 2014 и более ранних версий, см. в статье Документация по предыдущим версиям.
Типы возвращаемых данных
Примечания
Возвращает 0, если в предыдущей инструкции Transact-SQL не возникло ошибок.
Возвращает номер ошибки, если в предыдущей инструкции возникла ошибка. Если ошибка относится к представлению каталога sys.messages, @@ERROR содержит значение столбца sys.messages.message_id для этой ошибки. Можно просмотреть текст, связанный с номером ошибки @@ERROR в sys.messages.
Поскольку функция @@ERROR очищается и сбрасывается для каждой выполняемой инструкции, проверяйте ее сразу после инструкции или сохраните значение в локальную переменную для последующей проверки.
Для обработки ошибок используйте конструкцию TRY. CATCH. Конструкция TRY. CATCH также поддерживает дополнительные системные функции (ERROR_LINE, ERROR_MESSAGE, ERROR_PROCEDURE, ERROR_SEVERITY и ERROR_STATE), возвращающие более подробные сведения, чем @@ERROR. Кроме того, TRY. CATCH поддерживает функцию ERROR_NUMBER, которая не ограничена тем, что возвращает номер ошибки немедленно после выполнения инструкции. Дополнительные сведения см. в разделе TRY. CATCH (Transact-SQL).
Примеры
A. Использование функции @@ERROR для обнаружения конкретной ошибки
В следующем примере функция @@ERROR используется для проверки проверочного ограничения (ошибка 547) в инструкции UPDATE .
Б. Использование функции @@ERROR для выхода из процедуры по условию
В приведенном ниже примере инструкции IF. ELSE выполняют проверку @@ERROR после инструкции DELETE в хранимой процедуре. Значение переменной @@ERROR определяет код возврата, который отправляется вызывающей программе и указывает на успешное или неуспешное выполнение процедуры.
В. Использование функции @@ERROR с @@ROWCOUNT
В следующем примере инструкция @@ERROR с @@ROWCOUNT используется для проверки операции инструкции UPDATE . Значение @@ERROR проверяется на ошибки, а @@ROWCOUNT обеспечивает успешное применение обновления к строке таблицы.
Источник
ERROR_MESSAGE (Transact-SQL)
Область применения: SQL Server (все поддерживаемые версии) База данных SQL Azure Управляемый экземпляр SQL Azure Azure Synapse Analytics Analytics Platform System (PDW)
Эта функция возвращает текст сообщения об ошибке, которая вызвала выполнение блока CATCH конструкции TRY. CATCH.
Соглашения о синтаксисе Transact-SQL
Синтаксис
Ссылки на описание синтаксиса Transact-SQL для SQL Server 2014 и более ранних версий, см. в статье Документация по предыдущим версиям.
Типы возвращаемых данных
nvarchar(4000)
Возвращаемое значение
При вызове в блоке CATCH функция ERROR_MESSAGE возвращает полный текст сообщения об ошибке, запустившей блок CATCH . Текст содержит значения подставляемых параметров, таких как длина, имена объектов или время.
Функция ERROR_MESSAGE возвращает значение NULL в случае вызова вне блока CATCH.
Функцию ERROR_MESSAGE можно вызывать в любом месте области действия блока CATCH.
Функция ERROR_MESSAGE возвращает соответствующее сообщение об ошибке независимо от количества ее выполнений или от места ее вызова в области действия блока CATCH . В этом ее отличие от таких функций, как @@ERROR, которые возвращают номер ошибки только в той инструкции, которая непосредственно следует за инструкцией, вызвавшей ошибку.
Во вложенных блоках CATCH функция ERROR_MESSAGE возвращает сообщение об ошибке, соответствующее области действия блока CATCH , который ссылался на данный блок CATCH . Например, блок CATCH внешней конструкции TRY. CATCH может содержать внутреннюю конструкцию TRY. CATCH . Во внутреннем блоке CATCH функция ERROR_MESSAGE возвращает сообщение об ошибке, вызвавшей внутренний блок CATCH . Если функция ERROR_MESSAGE выполняется во внешнем блоке CATCH , она возвращает сообщение об ошибке, вызвавшей внешний блок CATCH .
Примеры
A. Использование функции ERROR_MESSAGE в блоке CATCH
В приведенном ниже примере показана инструкция SELECT , вызывающая ошибку деления на ноль. Блок CATCH возвращает сообщение об ошибке.
Б. Использование функции ERROR_MESSAGE в блоке CATCH с другими средствами обработки ошибок
В приведенном ниже примере показана инструкция SELECT , вызывающая ошибку деления на ноль. Вместе с сообщением об ошибке блок CATCH возвращает сведения о ней.
Источник
ERROR_MESSAGE (Transact-SQL)
Applies to: SQL Server (all supported versions) Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW)
This function returns the message text of the error that caused the CATCH block of a TRY. CATCH construct to execute.
Transact-SQL syntax conventions
Syntax
To view Transact-SQL syntax for SQL Server 2014 and earlier, see Previous versions documentation.
Return Types
nvarchar(4000)
Return Value
When called in a CATCH block, ERROR_MESSAGE returns the complete text of the error message that caused the CATCH block to run. The text includes the values supplied for any substitutable parameters — for example, lengths, object names, or times.
ERROR_MESSAGE returns NULL when called outside the scope of a CATCH block.
ERROR_MESSAGE supports calls anywhere within the scope of a CATCH block.
ERROR_MESSAGE returns a relevant error message regardless of how many times it runs, or where it runs within the scope of the CATCH block. This contrasts with a function like @@ERROR, which only returns an error number in the statement immediately following the one that causes an error.
In nested CATCH blocks, ERROR_MESSAGE returns the error message specific to the scope of the CATCH block that referenced that CATCH block. For example, the CATCH block of an outer TRY. CATCH construct could have an inner TRY. CATCH construct. Inside that inner CATCH block, ERROR_MESSAGE returns the message from the error that invoked the inner CATCH block. If ERROR_MESSAGE runs in the outer CATCH block, it returns the message from the error that invoked that outer CATCH block.
Examples
A. Using ERROR_MESSAGE in a CATCH block
This example shows a SELECT statement that generates a divide-by-zero error. The CATCH block returns the error message.
Here is the result set.
B. Using ERROR_MESSAGE in a CATCH block with other error-handling tools
This example shows a SELECT statement that generates a divide-by-zero error. Along with the error message, the CATCH block returns information about that error.
Источник
[Перевод] Обработка ошибок и транзакций в SQL Server. Часть 1. Обработка ошибок – быстрый старт
Привет, Хабр! Представляю вашему вниманию перевод статьи «Error and Transaction Handling in SQL Server. Part One – Jumpstart Error Handling» автора Erland Sommarskog.
1. Введение
Эта статья – первая в серии из трёх статей, посвященных обработке ошибок и транзакций в SQL Server. Её цель – дать вам быстрый старт в теме обработки ошибок, показав базовый пример, который подходит для большей части вашего кода. Эта часть написана в расчете на неопытного читателя, и по этой причине я намеренно умалчиваю о многих деталях. В данный момент задача состоит в том, чтобы рассказать как без упора на почему. Если вы принимаете мои слова на веру, вы можете прочесть только эту часть и отложить остальные две для дальнейших этапов в вашей карьере.
С другой стороны, если вы ставите под сомнение мои рекомендации, вам определенно необходимо прочитать две остальные части, где я погружаюсь в детали намного более глубоко, исследуя очень запутанный мир обработки ошибок и транзакций в SQL Server. Вторая и третья части, так же, как и три приложения, предназначены для читателей с более глубоким опытом. Первая статья — короткая, вторая и третья значительно длиннее.
Все статьи описывают обработку ошибок и транзакций в SQL Server для версии 2005 и более поздних версий.
1.1 Зачем нужна обработка ошибок?
Почему мы обрабатываем ошибки в нашем коде? На это есть много причин. Например, на формах в приложении мы проверяем введенные данные и информируем пользователей о допущенных при вводе ошибках. Ошибки пользователя – это предвиденные ошибки. Но нам также нужно обрабатывать непредвиденные ошибки. То есть, ошибки могут возникнуть из-за того, что мы что-то упустили при написании кода. Простой подход – это прервать выполнение или хотя бы вернуться на этап, в котором мы имеем полный контроль над происходящим. Недостаточно будет просто подчеркнуть, что совершенно непозволительно игнорировать непредвиденные ошибки. Это недостаток, который может вызвать губительные последствия: например, стать причиной того, что приложение будет предоставлять некорректную информацию пользователю или, что еще хуже, сохранять некорректные данные в базе. Также важно сообщать о возникновении ошибки с той целью, чтобы пользователь не думал о том, что операция прошла успешно, в то время как ваш код на самом деле ничего не выполнил.
Мы часто хотим, чтобы в базе данных изменения были атомарными. Например, задача по переводу денег с одного счета на другой. С этой целью мы должны изменить две записи в таблице CashHoldings и добавить две записи в таблицу Transactions. Абсолютно недопустимо, чтобы ошибки или сбой привели к тому, что деньги будут переведены на счет получателя, а со счета отправителя они не будут списаны. По этой причине обработка ошибок также касается и обработки транзакций. В приведенном примере нам нужно обернуть операцию в BEGIN TRANSACTION и COMMIT TRANSACTION, но не только это: в случае ошибки мы должны убедиться, что транзакция откачена.
2. Основные команды
Мы начнем с обзора наиболее важных команд, которые необходимы для обработки ошибок. Во второй части я опишу все команды, относящиеся к обработке ошибок и транзакций.
2.1 TRY-CATCH
Основным механизмом обработки ошибок является конструкция TRY-CATCH, очень напоминающая подобные конструкции в других языках. Структура такова:
Если какая-либо ошибка появится в , выполнение будет переведено в блок CATCH, и будет выполнен код обработки ошибок.
Как правило, в CATCH откатывают любую открытую транзакцию и повторно вызывают ошибку. Таким образом, вызывающая клиентская программа понимает, что что-то пошло не так. Повторный вызов ошибки мы обсудим позже в этой статье.
Вот очень быстрый пример:
Результат выполнения: This is the error: Divide by zero error encountered.
Мы вернемся к функции error_message() позднее. Стоит отметить, что использование PRINT в обработчике CATCH приводится только в рамках экспериментов и не следует делать так в коде реального приложения.
Если вызывает хранимую процедуру или запускает триггеры, то любая ошибка, которая в них возникнет, передаст выполнение в блок CATCH. Если более точно, то, когда возникает ошибка, SQL Server раскручивает стек до тех пор, пока не найдёт обработчик CATCH. И если такого обработчика нет, SQL Server отправляет сообщение об ошибке напрямую клиенту.
Есть одно очень важное ограничение у конструкции TRY-CATCH, которое нужно знать: она не ловит ошибки компиляции, которые возникают в той же области видимости. Рассмотрим пример:
Как можно видеть, блок TRY присутствует, но при возникновении ошибки выполнение не передается блоку CATCH, как это ожидалось. Это применимо ко всем ошибкам компиляции, таким как пропуск колонок, некорректные псевдонимы и тому подобное, которые возникают во время выполнения. (Ошибки компиляции могут возникнуть в SQL Server во время выполнения из-за отложенного разрешения имен – особенность, благодаря которой SQL Server позволяет создать процедуру, которая обращается к несуществующим таблицам.)
Эти ошибки не являются полностью неуловимыми; вы не можете поймать их в области, в которой они возникают, но вы можете поймать их во внешней области. Добавим такой код к предыдущему примеру:
Теперь мы получим на выходе это:
На этот раз ошибка была перехвачена, потому что сработал внешний обработчик CATCH.
2.2 SET XACT_ABORT ON
В начало ваших хранимых процедур следует всегда добавлять это выражение:
Оно активирует два параметра сессии, которые выключены по умолчанию в целях совместимости с предыдущими версиями, но опыт доказывает, что лучший подход – это иметь эти параметры всегда включенными. Поведение SQL Server по умолчанию в той ситуации, когда не используется TRY-CATCH, заключается в том, что некоторые ошибки прерывают выполнение и откатывают любые открытые транзакции, в то время как с другими ошибками выполнение последующих инструкций продолжается. Когда вы включаете XACT_ABORT ON, почти все ошибки начинают вызывать одинаковый эффект: любая открытая транзакция откатывается, и выполнение кода прерывается. Есть несколько исключений, среди которых наиболее заметным является выражение RAISERROR.
Параметр XACT_ABORT необходим для более надежной обработки ошибок и транзакций. В частности, при настройках по умолчанию есть несколько ситуаций, когда выполнение может быть прервано без какого-либо отката транзакции, даже если у вас есть TRY-CATCH. Мы видели такой пример в предыдущем разделе, где мы выяснили, что TRY-CATCH не перехватывает ошибки компиляции, возникшие в той же области. Открытая транзакция, которая не была откачена из-за ошибки, может вызвать серьезные проблемы, если приложение работает дальше без завершения транзакции или ее отката.
Для надежной обработки ошибок в SQL Server вам необходимы как TRY-CATCH, так и SET XACT_ABORT ON. Среди них инструкция SET XACT_ABORT ON наиболее важна. Если для кода на промышленной среде только на нее полагаться не стоит, то для быстрых и простых решений она вполне подходит.
Параметр NOCOUNT не имеет к обработке ошибок никакого отношения, но включение его в код является хорошей практикой. NOCOUNT подавляет сообщения вида (1 row(s) affected), которые вы можете видеть в панели Message в SQL Server Management Studio. В то время как эти сообщения могут быть полезны при работе c SSMS, они могут негативно повлиять на производительность в приложении, так как увеличивают сетевой трафик. Сообщение о количестве строк также может привести к ошибке в плохо написанных клиентских приложениях, которые могут подумать, что это данные, которые вернул запрос.
Выше я использовал синтаксис, который немного необычен. Большинство людей написали бы два отдельных выражения:
Между ними нет никакого отличия. Я предпочитаю версию с SET и запятой, т.к. это снижает уровень шума в коде. Поскольку эти выражения должны появляться во всех ваших хранимых процедурах, они должны занимать как можно меньше места.
3. Основной пример обработки ошибок
После того, как мы посмотрели на TRY-CATCH и SET XACT_ABORT ON, давайте соединим их вместе в примере, который мы можем использовать во всех наших хранимых процедурах. Для начала я покажу пример, в котором ошибка генерируется в простой форме, а в следующем разделе я рассмотрю решения получше.
Для примера я буду использовать эту простую таблицу.
Вот хранимая процедура, которая демонстрирует, как вы должны работать с ошибками и транзакциями.
Первая строка в процедуре включает XACT_ABORT и NOCOUNT в одном выражении, как я показывал выше. Эта строка – единственная перед BEGIN TRY. Все остальное в процедуре должно располагаться после BEGIN TRY: объявление переменных, создание временных таблиц, табличных переменных, всё. Даже если у вас есть другие SET-команды в процедуре (хотя причины для этого встречаются редко), они должны идти после BEGIN TRY.
Причина, по которой я предпочитаю указывать SET XACT_ABORT и NOCOUNT перед BEGIN TRY, заключается в том, что я рассматриваю это как одну строку шума: она всегда должна быть там, но я не хочу, чтобы это мешало взгляду. Конечно же, это дело вкуса, и если вы предпочитаете ставить SET-команды после BEGIN TRY, ничего страшного. Важно то, что вам не следует ставить что-либо другое перед BEGIN TRY.
Часть между BEGIN TRY и END TRY является основной составляющей процедуры. Поскольку я хотел использовать транзакцию, определенную пользователем, я ввел довольно надуманное бизнес-правило, в котором говорится, что если вы вставляете пару, то обратная пара также должна быть вставлена. Два выражения INSERT находятся внутри BEGIN и COMMIT TRANSACTION. Во многих случаях у вас будет много строк кода между BEGIN TRY и BEGIN TRANSACTION. Иногда у вас также будет код между COMMIT TRANSACTION и END TRY, хотя обычно это только финальный SELECT, возвращающий данные или присваивающий значения выходным параметрам. Если ваша процедура не выполняет каких-либо изменений или имеет только одно выражение INSERT/UPDATE/DELETE/MERGE, то обычно вам вообще не нужно явно указывать транзакцию.
В то время как блок TRY будет выглядеть по-разному от процедуры к процедуре, блок CATCH должен быть более или менее результатом копирования и вставки. То есть вы делаете что-то короткое и простое и затем используете повсюду, не особо задумываясь. Обработчик CATCH, приведенный выше, выполняет три действия:
- Откатывает любые открытые транзакции.
- Повторно вызывает ошибку.
- Убеждается, что возвращаемое процедурой значение отлично от нуля.
Эти три действия должны всегда быть там. Мы можете возразить, что строка
не нужна, если нет явной транзакции в процедуре, но это абсолютно неверно. Возможно, вы вызываете хранимую процедуру, которая открывает транзакцию, но которая не может ее откатить из-за ограничений TRY-CATCH. Возможно, вы или кто-то другой добавите явную транзакцию через два года. Вспомните ли вы тогда о том, что нужно добавить строку с откатом? Не рассчитывайте на это. Я также слышу читателей, которые возражают, что если тот, кто вызывает процедуру, открыл транзакцию, мы не должны ее откатывать… Нет, мы должны, и если вы хотите знать почему, вам нужно прочитать вторую и третью части. Откат транзакции в обработчике CATCH – это категорический императив, у которого нет исключений.
Код повторной генерации ошибки включает такую строку:
Встроенная функция error_message() возвращает текст возникшей ошибки. В следующей строке ошибка повторно вызывается с помощью выражения RAISERROR. Это не самый простой способ вызова ошибки, но он работает. Другие способы мы рассмотрим в следующей главе.
Замечание: синтаксис для присвоения начального значения переменной в DECLARE был внедрен в SQL Server 2008. Если у вас SQL Server 2005, вам нужно разбить строку на DECLARE и выражение SELECT.
Финальное выражение RETURN – это страховка. RAISERROR никогда не прерывает выполнение, поэтому выполнение следующего выражения будет продолжено. Пока все процедуры используют TRY-CATCH, а также весь клиентский код обрабатывает исключения, нет повода для беспокойства. Но ваша процедура может быть вызвана из старого кода, написанного до SQL Server 2005 и до внедрения TRY-CATCH. В те времена лучшее, что мы могли делать, это смотреть на возвращаемые значения. То, что вы возвращаете с помощью RETURN, не имеет особого значения, если это не нулевое значение (ноль обычно обозначает успешное завершение работы).
Последнее выражение в процедуре – это END CATCH. Никогда не следует помещать какой-либо код после END CATCH. Кто-нибудь, читающий процедуру, может не увидеть этот кусок кода.
После прочтения теории давайте попробуем тестовый пример:
Давайте добавим внешнюю процедуру для того, чтобы увидеть, что происходит при повторном вызове ошибки:
Мы получили корректное сообщение об ошибке, но если вы посмотрите на заголовки этого сообщения и на предыдущее поближе, то можете заметить проблему:
Сообщение об ошибке выводит информацию о расположении конечного выражения RAISERROR. В первом случае некорректен только номер строки. Во втором случае некорректно также имя процедуры. Для простых процедур, таких как наш тестовый пример, это не является большой проблемой. Но если у вас есть несколько уровней вложенных сложных процедур, то наличие сообщения об ошибке с отсутствием указания на место её возникновения сделает поиск и устранение ошибки намного более сложным делом. По этой причине желательно генерировать ошибку таким образом, чтобы можно было определить нахождение ошибочного фрагмента кода быстро, и это то, что мы рассмотрим в следующей главе.
4. Три способа генерации ошибки
4.1 Использование error_handler_sp
Мы рассмотрели функцию error_message(), которая возвращает текст сообщения об ошибке. Сообщение об ошибке состоит из нескольких компонентов, и существует своя функция error_xxx() для каждого из них. Мы можем использовать их для повторной генерации полного сообщения, которое содержит оригинальную информацию, хотя и в другом формате. Если делать это в каждом обработчике CATCH, это будет большой недостаток — дублирование кода. Вам не обязательно находиться в блоке CATCH для вызова error_message() и других подобных функций, и они вернут ту же самую информацию, если будут вызваны из хранимой процедуры, которую выполнит блок CATCH.
Позвольте представить вам error_handler_sp:
Первое из того, что делает error_handler_sp – это сохраняет значение всех error_xxx() функций в локальные переменные. Я вернусь к выражению IF через секунду. Вместо него давайте посмотрим на выражение SELECT внутри IF:
Цель этого SELECT заключается в форматировании сообщения об ошибке, которое передается в RAISERROR. Оно включает в себя всю информацию из оригинального сообщения об ошибке, которое мы не можем вставить напрямую в RAISERROR. Мы должны обработать имя процедуры, которое может быть NULL для ошибок в обычных скриптах или в динамическом SQL. Поэтому используется функция COALESCE. (Если вы не понимаете форму выражения RAISERROR, я рассказываю о нем более детально во второй части.)
Отформатированное сообщение об ошибке начинается с трех звездочек. Этим достигаются две цели: 1) Мы можем сразу видеть, что это сообщение вызвано из обработчика CATCH. 2) Это дает возможность для error_handler_sp отфильтровать ошибки, которые уже были сгенерированы один или более раз, с помощью условия NOT LIKE ‘***%’ для того, чтобы избежать изменения сообщения во второй раз.
Вот как обработчик CATCH должен выглядеть, когда вы используете error_handler_sp:
Давайте попробуем несколько тестовых сценариев.
Заголовки сообщений говорят о том, что ошибка возникла в процедуре error_handler_sp, но текст сообщений об ошибках дает нам настоящее местонахождение ошибки – как название процедуры, так и номер строки.
Я покажу еще два метода вызова ошибок. Однако error_handler_sp является моей главной рекомендацией для читателей, которые читают эту часть. Это — простой вариант, который работает на всех версиях SQL Server начиная с 2005. Существует только один недостаток: в некоторых случаях SQL Server генерирует два сообщения об ошибках, но функции error_xxx() возвращают только одну из них, и поэтому одно из сообщений теряется. Это может быть неудобно при работе с административными командами наподобие BACKUPRESTORE, но проблема редко возникает в коде, предназначенном чисто для приложений.
4.2. Использование ;THROW
В SQL Server 2012 Microsoft представил выражение ;THROW для более легкой обработки ошибок. К сожалению, Microsoft сделал серьезную ошибку при проектировании этой команды и создал опасную ловушку.
С выражением ;THROW вам не нужно никаких хранимых процедур. Ваш обработчик CATCH становится таким же простым, как этот:
Достоинство ;THROW в том, что сообщение об ошибке генерируется точно таким же, как и оригинальное сообщение. Если изначально было два сообщения об ошибках, оба сообщения воспроизводятся, что делает это выражение еще привлекательнее. Как и со всеми другими сообщениями об ошибках, ошибки, сгенерированные ;THROW, могут быть перехвачены внешним обработчиком CATCH и воспроизведены. Если обработчика CATCH нет, выполнение прерывается, поэтому оператор RETURN в данном случае оказывается не нужным. (Я все еще рекомендую оставлять его, на случай, если вы измените свое отношение к ;THROW позже).
Если у вас SQL Server 2012 или более поздняя версия, измените определение insert_data и outer_sp и попробуйте выполнить тесты еще раз. Результат в этот раз будет такой:
Имя процедуры и номер строки верны и нет никакого другого имени процедуры, которое может нас запутать. Также сохранены оригинальные номера ошибок.
В этом месте вы можете сказать себе: действительно ли Microsoft назвал команду ;THROW? Разве это не просто THROW? На самом деле, если вы посмотрите в Books Online, там не будет точки с запятой. Но точка с запятой должны быть. Официально они отделяют предыдущее выражение, но это опционально, и далеко не все используют точку с запятой в выражениях T-SQL. Более важно, что если вы пропустите точку с запятой перед THROW, то не будет никакой синтаксической ошибки. Но это повлияет на поведение при выполнении выражения, и это поведение будет непостижимым для непосвященных. При наличии активной транзакции вы получите сообщение об ошибке, которое будет полностью отличаться от оригинального. И еще хуже, что при отсутствии активной транзакции ошибка будет тихо выведена без обработки. Такая вещь, как пропуск точки с запятой, не должно иметь таких абсурдных последствий. Для уменьшения риска такого поведения, всегда думайте о команде как о ;THROW (с точкой с запятой).
Нельзя отрицать того, что ;THROW имеет свои преимущества, но точка с запятой не единственная ловушка этой команды. Если вы хотите использовать ее, я призываю вас прочитать по крайней мере вторую часть этой серии, где я раскрываю больше деталей о команде ;THROW. До этого момента, используйте error_handler_sp.
4.3. Использование SqlEventLog
Третий способ обработки ошибок – это использование SqlEventLog, который я описываю очень детально в третьей части. Здесь я лишь сделаю короткий обзор.
SqlEventLog предоставляет хранимую процедуру slog.catchhandler_sp, которая работает так же, как и error_handler_sp: она использует функции error_xxx() для сбора информации и выводит сообщение об ошибке, сохраняя всю информацию о ней. Вдобавок к этому, она логирует ошибку в таблицу splog.sqleventlog. В зависимости от типа приложения, которое у вас есть, эта таблица может быть очень ценным объектом.
Для использования SqlEventLog, ваш обработчик CATCH должен быть таким:
@@procid возвращает идентификатор объекта текущей хранимой процедуры. Это то, что SqlEventLog использует для логирования информации в таблицу. Используя те же тестовые сценарии, получим результат их работы с использованием catchhandler_sp:
Как вы видите, сообщение об ошибке отформатировано немного не так, как это делает error_handler_sp, но основная идея такая же. Вот образец того, что было записано в таблицу slog.sqleventlog:
logid | logdate | errno | severity | logproc | linenum | msgtext |
1 | 2015-01-25 22:40:24.393 | 515 | 16 | insert_data | 5 | Cannot insert . |
2 | 2015-01-25 22:40:24.395 | 2627 | 14 | insert_data | 6 | Violation of . |
Если вы хотите попробовать SqlEventLog, вы можете загрузить файл sqleventlog.zip. Инструкция по установке находится в третьей части, раздел Установка SqlEventLog.
5. Финальные замечания
Вы изучили основной образец для обработки ошибок и транзакций в хранимых процедурах. Он не идеален, но он должен работать в 90-95% вашего кода. Есть несколько ограничений, на которые стоит обратить внимание:
- Как мы видели, ошибки компиляции не могут быть перехвачены в той же процедуре, в которой они возникли, а только во внешней процедуре.
- Пример не работает с пользовательскими функциями, так как ни TRY-CATCH, ни RAISERROR нельзя в них использовать.
- Когда хранимая процедура на Linked Server вызывает ошибку, эта ошибка может миновать обработчик в хранимой процедуре на локальном сервере и отправиться напрямую клиенту.
- Когда процедура вызвана как INSERT-EXEC, вы получите неприятную ошибку, потому что ROLLBACK TRANSACTION не допускается в данном случае.
- Как упомянуто выше, если вы используете error_handler_sp или SqlEventLog, мы потеряете одно сообщение, когда SQL Server выдаст два сообщения для одной ошибки. При использовании ;THROW такой проблемы нет.
Я рассказываю об этих ситуациях более подробно в других статьях этой серии.
Перед тем как закончить, я хочу кратко коснуться триггеров и клиентского кода.
Триггеры
Пример для обработки ошибок в триггерах не сильно отличается от того, что используется в хранимых процедурах, за исключением одной маленькой детали: вы не должны использовать выражение RETURN (потому что RETURN не допускается использовать в триггерах).
С триггерами важно понимать, что они являются частью команды, которая запустила триггер, и в триггере вы находитесь внутри транзакции, даже если не используете BEGIN TRANSACTION.
Иногда я вижу на форумах людей, которые спрашивают, могут ли они написать триггер, который не откатывает в случае падения запустившую его команду. Ответ таков: нет способа сделать это надежно, поэтому не стоит даже пытаться. Если в этом есть необходимость, по возможности не следует использовать триггер вообще, а найти другое решение. Во второй и третьей частях я рассматриваю обработку ошибок в триггерах более подробно.
Клиентский код
У вас должна быть обработка ошибок в коде клиента, если он имеет доступ к базе. То есть вы должны всегда предполагать, что при любом вызове что-то может пойти не так. Как именно внедрить обработку ошибок, зависит от конкретной среды.
Здесь я только обращу внимание на важную вещь: реакцией на ошибку, возвращенную SQL Server, должно быть завершение запроса во избежание открытых бесхозных транзакций:
Это также применимо к знаменитому сообщению Timeout expired (которое является не сообщением от SQL Server, а от API).
6. Конец первой части
Это конец первой из трех частей серии. Если вы хотели изучить вопрос обработки ошибок быстро, вы можете закончить чтение здесь. Если вы настроены идти дальше, вам следует прочитать вторую часть, где наше путешествие по запутанным джунглям обработки ошибок и транзакций в SQL Server начинается по-настоящему.
… и не забывайте добавлять эту строку в начало ваших хранимых процедур:
Источник
There are about 98000 error messages as of SQL Server 2008 – including repitions for all the languages supported.
sys.messages catalog view represents one row per error message.
You can simply run select * from sys.messages to see all the error messages. You can see that every message has a unique message_id and the description in text column.
Another interesting column is serverity. When an error is raised by the SQL Server Database Engine, the severity of the error indicates the type of problem encountered by SQL Server.
Following are the severity levels:
0-10
These are only Informational messages.
11-16
Errors that can be corrected by the user.
Example: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
11
A given object does not exist.
Example: Table ‘%.*ls’ does not exist.
12
Indicates that queries are not requesting locks since they are using query hints.
Example: Could not continue scan with NOLOCK due to data movement.
13
Transaction deadlock errors.
Example: Transaction (Process ID %d) was deadlocked on %.*ls resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
14
Security-related errors.
Example: The %ls permission was denied on the object ‘%.*ls’, database ‘%.*ls’, schema ‘%.*ls’.
15
Syntax errors in T-SQL
Example: A TOP N value may not be negative.
16
Errors that can be corrected by the user.
17-19
Indicate software errors that cannot be corrected by the user.
17
Indicates that the statement caused SQL Server to run out of resources (such as memory, locks, or disk space for the database) or to exceed some limit set by the system administrator.
Example: Time-out occurred while waiting for buffer latch type %d for page %S_PGID, database ID %d.
18
Indicates an issue in the Database Engine
Example: Replication-%s: agent %s failed. %s
19
Indicates that a non-configurable Database Engine limit has been exceeded. The current batch gets terminated. Error messages with a severity level from 19 through 25 are written to the error log.
Example: There is insufficient system memory in resource pool ‘%ls’ to run this query.
20-25
These errors indicate system problems and are fatal errors. Error messages with a severity level from 19 through 25 are written to the error log.
Example: Unable to deallocate a kept page.
20
Indicates that a statement has encountered a problem. Because the problem has affected only the current task, it is unlikely that the database itself has been damaged.
Example: Warning: Fatal error %d occurred at %S_DATE. Note the error and time, and contact your system administrator.
21
Unlike 20, this one indicates that a problem has been encountered that affects all tasks in the current database.
Example: An error occurred while writing an audit trace. SQL Server is shutting down. Check and correct error conditions such as insufficient disk space, and then restart SQL Server. If the problem persists, disable auditing by starting the server at the command prompt with the “-f” switch, and using SP_CONFIGURE.
22
Indicates that the table or index specified in the message has been damaged by a software or hardware problem.
Example: The row object is inconsistent. Please rerun the query.
23
Integrity of the entire database is in question because of a hardware or software problem.
Example: Possible schema corruption. Run DBCC CHECKCATALOG.
24
Indicates a media failure.
Example: The log record at LSN %S_LSN is corrupted.
Hope you like it.
Regards
Rahul Sharma
Like us on FaceBook | Follow us on Twitter | Join the fastest growing SQL Server group on FaceBook
Follow me on Twitter | Follow me on FaceBook
Error | Severity | Description |
1 | 10 | Version date of last upgrade: 10/11/90. |
21 | 10 | Warning: Fatal error %d occurred at %S_DATE. Note the error and time, and contact your system administrator. |
53 | 10 | An error has occurred while establishing a connection to the server. When connecting to SQL Server, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: Named Pipes Provider, error: 40 — Could not open a connection to SQL Server ) (.Net SqlClient Data Provider). |
101 | 15 | Query not allowed in Waitfor. |
102 | 15 | Incorrect syntax near ‘%.*ls’. |
103 | 15 | The %S_MSG that starts with ‘%.*ls’ is too long. Maximum length is %d. |
104 | 15 | ORDER BY items must appear in the select list if the statement contains a UNION operator. |
105 | 15 | Unclosed quotation mark before the character string ‘%.*ls’. |
106 | 16 | Too many table names in the query. The maximum allowable is %d. |
107 | 15 | The column prefix ‘%.*ls’ does not match with a table name or alias name used in the query. |
108 | 15 | The ORDER BY position number is out of range of the number of items in the select list. |
109 | 15 | There are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement. |
110 | 15 | There are fewer columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement. |
111 | 15 | ‘CREATE FUNCTION’ must be the first statement in a query batch. |
112 | 15 | Variables are not allowed in the %ls statement. |
113 | 15 | Missing end comment mark ‘*/’. |
114 | 15 | Browse mode is invalid for a statement that assigns values to a variable. |
115 | 15 | The FOR UPDATE clause is invalid for statements containing set operators. |
116 | 15 | Only one expression can be specified in the select list when the subquery is not introduced with EXISTS. |
117 | 15 | The object name «Object Name» contains more than the maximum number of prefixes. The maximum is 2. |
118 | 15 | Only members of the sysadmin role can specify the %ls option for the %ls statement. |
119 | 15 | Must pass parameter number %d and subsequent parameters as ‘@name = value’. After the form ‘@name = value’ has been used, all subsequent parameters must be passed in the form ‘@name = value’. |
120 | 15 | The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns. |
121 | 15 | The select list for the INSERT statement contains more items than the insert list. The number of SELECT values must match the number of INSERT columns. |
122 | 15 | The %ls option is allowed only with %ls syntax. |
123 | 15 | Batch/procedure exceeds maximum length of %d characters. |
124 | 15 | CREATE PROCEDURE contains no statements. |
125 | 15 | Case expressions may only be nested to level %d. |
126 | 15 | Invalid pseudocolumn «%.*ls». |
127 | 15 | A TOP N value may not be negative. |
128 | 15 | The name ‘<Column Name>’ is not permitted in this context. Only constants, expressions, or variables allowed here. Column names are not permitted. |
129 | 15 | Fillfactor %d is not a valid percentage; fillfactor must be between 1 and 100. |
130 | 16 | Cannot perform an aggregate function on an expression containing an aggregate or a subquery. |
131 | 15 |
The size (<Data Type Size>) given to the type ‘varchar / char / nvarchar / nchar / binary / varbinary’ exceeds the maximum allowed for any data type (8000). The size (<Data Type Size>) given to the column ‘<Column Name>’ exceeds the maximum allowed for any data type (8000). |
132 | 15 | The label ‘%.*ls’ has already been declared. Label names must be unique within a query batch or stored procedure. |
133 | 15 | A GOTO statement references the label ‘<Label Name>’ but the label has not been declared. |
134 | 15 | The variable name ‘%.*ls’ has already been declared. Variable names must be unique within a query batch or stored procedure. |
135 | 15 | Cannot use a BREAK statement outside the scope of a WHILE statement. |
136 | 15 | Cannot use a CONTINUE statement outside the scope of a WHILE statement. |
137 | 15 | Must declare the scalar variable ‘<Variable Name>’. |
138 | 15 | Correlation clause in a subquery not permitted. |
139 | 15 | Cannot assign a default value to a local variable. |
140 | 15 | Can only use IF UPDATE within a CREATE TRIGGER statement. |
141 | 15 | A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations. |
142 | 15 | Incorrect syntax for definition of the ‘%ls’ constraint. |
143 | 15 | A COMPUTE BY item was not found in the order by list. All expressions in the compute by list must also be present in the order by list. |
144 | 15 | Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause. |
145 | 15 | ORDER BY items must appear in the select list if SELECT DISTINCT is specified. |
146 | 15 | Could not allocate ancillary table for a subquery. Maximum number of tables in a query (%d) exceeded. |
147 | 15 | An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference. |
148 | 15 | Incorrect time syntax in time string ‘<Wait Time>’ used with WAITFOR. |
149 | 15 | Time value ‘%.*ls’ used with WAITFOR is not a valid value. Check date/time syntax. |
150 | 15 | Both terms of an outer join must contain columns. |
151 | 15 | ‘%.*ls’ is an invalid money value. |
152 | 15 | The same large data placement option «%.*ls» has been specified twice. |
153 | 15 | Invalid usage of the option %.*ls in the %ls statement. |
154 | 15 | a COMPUTE clause is not allowed in a SELECT INTO statement. |
155 | 15 | ‘<DATEADD option>’ is not a recognized DATEADD option. |
156 | 15 | Incorrect syntax near the keyword ‘%.*ls’. |
157 | 15 | An aggregate may not appear in the set list of an UPDATE statement. |
158 | 15 | An aggregate may not appear in the OUTPUT clause. |
159 | 15 |
SQL Server 2005, SQL Server 2008 — Must specify the table name and index name for the DROP INDEX statement. SQL Server 2000 — For DROP INDEX, you must give both the table and the index name, in the form tablename.indexname. |
160 | 15 | Rule does not contain a variable. |
161 | 15 | Rule contains more than one variable. |
162 | 15 | Invalid expression in the TOP clause. |
163 | 15 | The compute by list does not match the order by list. |
164 | 15 | Each GROUP BY expression must contain at least one column that is not an outer reference. GROUP BY expressions must refer to column names that appear in the select list. |
165 | 16 | Privilege %ls may not be granted or revoked. |
166 | 15 | ‘CREATE VIEW’ does not allow specifying the database name as a prefix to the object name. |
167 | 16 | Cannot create a trigger on a temporary object. |
168 | 15 | The %S_MSG ‘%.*ls’ is out of the range of computer representation (%d bytes). |
169 | 15 | A column has been specified more than once in the order by list. Columns in the order by list must be unique. |
170 | 15 | Line %d: Incorrect syntax near ‘%.*ls’. |
171 | 15 | Cannot use SELECT INTO in browse mode. |
172 | 15 | Cannot use HOLDLOCK in browse mode. |
173 | 15 | The definition for column <Column Name> must include a data type. |
174 | 15 | The dateadd function requires 3 arguments. |
175 | 15 | An aggregate may not appear in a computed column expression or check constraint. |
176 | 15 | The FOR BROWSE clause is no longer supported in views. Set the database compatibility level to 80 or lower for this statement to be allowed. |
177 | 15 | The IDENTITY function can only be used when the SELECT statement has an INTO clause. |
178 | 15 | A RETURN statement with a return value cannot be used in this context. |
179 | 15 | Cannot use the OUTPUT option when passing a constant to a stored procedure. |
180 | 15 | There are too many parameters in this %ls statement. The maximum number is %d. |
181 | 15 |
SQL Server 2008 — Cannot use the OUTPUT option in a DECLARE, CREATE AGGREGATE or CREATE FUNCTION statement. SQL Server 2005 — Cannot use the OUTPUT option in a DECLARE or CREATE FUNCTION statement. SQL Server 2000 — Cannot use the OUTPUT option in a DECLARE statement. |
182 | 15 | Table and column names must be supplied for the READTEXT or WRITETEXT utility. |
183 | 15 | The scale (<Scale Value>) for column ‘<Column Name>’ must be within the range 0 to <Precision Value>. |
184 | 15 | DEFAULT cannot be specified more than once for filegroups of the same content type. |
185 | 15 | Data stream is invalid for WRITETEXT statement in bulk form. |
186 | 15 | Data stream missing from WRITETEXT statement. |
187 | 16 | The valid range for MAX_QUEUE_READERS is 0 to 32767. |
188 | 15 | Cannot specify a log device in a CREATE DATABASE statement without also specifying at least one non-log device. |
189 | 15 | The %ls function requires %d to %d arguments. |
190 | 15 | An invalid date or time was specified in the statement. |
191 | 15 | Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries. |
192 | 16 | The scale must be less than or equal to the precision. |
193 | 15 | The object or column name starting with ‘%.*ls’ is too long. The maximum length is %d characters. |
194 | 15 | A SELECT INTO statement cannot contain a SELECT statement that assigns values to a variable. |
195 | 15 | ‘Function Name’ is not a recognized function name. |
196 | 15 | SELECT INTO must be the first query in an SQL statement containing a UNION, INTERSECT or EXCEPT operator. |
197 | 15 | EXECUTE cannot be used as a source when inserting into a table variable. |
198 | 15 | Browse mode is invalid for statements containing a UNION operator. |
199 | 15 | An INSERT statement cannot contain a SELECT statement that assigns values to a variable. |
201 | 16 | Procedure ‘<Procedure Name>’ expects parameter ‘<Parameter Name>’, which was not supplied. |
202 | 16 | Invalid type ‘%s’ for WAITFOR. Supported data types are CHAR/VARCHAR, NCHAR/NVARCHAR, and DATETIME. WAITFOR DELAY supports the INT and SMALLINT data types. |
203 | 16 | The name ‘%.*ls’ is not a valid identifier. |
204 | 20 | Normalization error in node %ls. |
205 | 16 | All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists. |
206 | 16 | Operand type clash: %ls is incompatible with %ls |
207 | 16 | Invalid column name ‘%.*ls’. |
208 | 16 | Invalid object name ‘%.*ls’. |
209 | 16 | Ambiguous column name ‘%.*ls’. |
210 | 16 | Syntax error converting datetime from binary/varbinary string. |
211 | 12 | SyntaxPossible schema corruption. Run DBCC CHECKCATALOG. |
212 | 16 | Expression result length exceeds the maximum. %d max, %d found. |
213 | 16 | Insert Error: Column name or number of supplied values does not match table definition. |
214 | 16 | Procedure expects parameter ‘%ls’ of type ‘%ls’. |
215 | 16 | Parameters supplied for object ‘%.*ls’ which is not a function. If the parameters are intended as a table hint, a WITH keyword is required. |
216 | 16 | Parameters were not supplied for the function ‘%.*ls’. |
217 | 16 | Maximum stored procedure, function, trigger, or view nesting level exceeded (limit %d). |
218 | 16 | Could not find the type ‘%.*ls’. Either it does not exist or you do not have the necessary permission. |
219 | 16 | The type ‘%.*ls’ already exists, or you do not have permission to create it. |
220 | 16 | Arithmetic overflow error for data type %ls, value = %ld. |
221 | 10 | FIPS Warning: Implicit conversion from %ls to %ls. |
222 | 16 | The base type «%.*ls» is not a valid base type for the alias data type. |
223 | 11 | Object ID %ld specified as a default for table ID %ld, column ID %d is missing or not of type default. |
224 | 11 | Object ID %ld specified as a rule for table ID %ld, column ID %d is missing or not of type default. |
225 | 16 | The parameters supplied for the %ls «%.*ls» are not valid. |
226 | 16 | %ls statement not allowed within multi-statement transaction. |
227 | 15 | %.*ls is not a valid function, property, or field. |
228 | 15 | Method ‘%.*ls’ of type ‘%.*ls’ in assembly ‘%.*ls’ does not return any value. |
229 | 14 | %ls permission denied on object ‘%.*ls’, database ‘%.*ls’, owner ‘%.*ls’. |
230 | 14 | %ls permission denied on column ‘%.*ls’ of object ‘%.*ls’, database ‘%.*ls’, owner ‘%.*ls’. |
231 | 11 | No such default. ID = %ld, database ID = %d. |
232 | 16 | Arithmetic overflow error for type %ls, value = %f. |
233 | 16 | The column ‘%.*ls’ in table ‘%.*ls’ cannot be null. |
234 | 16 | There is insufficient result space to convert a money value to varchar / nvarchar / char / nchar. |
235 | 16 | Cannot convert a char value to money. The char value has incorrect syntax. |
236 | 16 | The conversion from char data type to money resulted in a money overflow error. |
237 | 16 | There is insufficient result space to convert a money value to int / smallint / tinyint. |
238 | 16 | There is insufficient result space to convert the %ls value (= %d) to the money data type. |
239 | 16 | Duplicate common table expression name ‘%.*ls’ was specified. |
240 | 16 | Types don’t match between the anchor and the recursive part in column «<Column Name>» of recursive query «<Recursive CTE>». |
241 | 16 | Syntax error converting datetime from character string. |
242 | 16 | The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value. |
243 | 16 | Type <Data Type> is not a defined system type. |
244 | 16 | The conversion of the %ls value ‘%.*ls’ overflowed an %hs column. Use a larger integer column. |
245 | 16 | Syntax error converting the varchar value to a column of data type int. |
246 | 16 | No anchor member was specified for recursive query «%.*ls». |
247 | 16 | An anchor member was found in the recursive part of recursive query «%.*ls». |
248 | 16 | The conversion of the %ls value ‘%.*ls’ overflowed an int column. Maximum integer value exceeded. |
249 | 16 | The type «%ls» is not comparable. It cannot be used in the %ls clause. |
Error | Severity | Description |
251 | 16 | Could not allocate ancillary table for query optimization. Maximum number of tables in a query (%d) exceeded. |
252 | 16 | Recursive common table expression ‘<Common Table Expression Name>’ does not contain a top-level UNION ALL operator. |
253 | 16 | Recursive member of a common table expression ‘<Common Table Expression Name>’ has multiple recursive references. |
254 | 16 | Prefixed columns are not allowed in the column list of a PIVOT operator. |
255 | 16 | Pseudocolumns are not allowed in the column list of a PIVOT operator. |
256 | 16 | The data type int is invalid for the substring function. Allowed types are: char/varchar, nchar/nvarchar, and binary/varbinary. |
257 | 16 | Implicit conversion from data type %ls to %ls is not allowed. Use the CONVERT function to run this query. |
258 | 16 | Cannot call methods on %ls. |
259 | 16 | Ad hoc updates to system catalogs are not enabled. The system administrator must reconfigure SQL Server to allow this. |
260 | 16 | Disallowed implicit conversion from data type %ls to data type %ls, table ‘%.*ls’, column ‘%.*ls’. Use the CONVERT function to run this query. |
261 | 16 | ‘%.*ls’ is not a recognized function. |
262 | 16 | %ls permission denied in database ‘%.*ls’. |
263 | 16 | Must specify table to select from. |
264 | 16 | Column name ‘%.*ls’ appears more than once in the result column list. |
265 | 16 | The column name «%.*ls» specified in the %ls operator conflicts with the existing column name in the %ls argument. |
266 | 16 | Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = %ld, current count = %ld. |
267 | 16 | Object ‘%.*ls’ cannot be found. |
268 | 16 | Cannot run SELECT INTO in this database. The database owner must run sp_dboption to enable this option. |
270 | 16 | Object ‘%.*ls’ cannot be modified. |
271 | 16 |
SQL Server 2005, SQL Server 2008, SQL Server 2012 — The column ‘<Column Name>’ cannot be modified because it is either a computed column or is the result of a UNION operator. SQL Server 2000 — Column ‘<Column Name>’ cannot be modified because it is a computed column. |
272 | 16 | Cannot update a timestamp column. |
273 | 16 | Cannot insert a non-null value into a timestamp column. Use INSERT with a column list or with a default of NULL for the timestamp column. |
275 | 16 | Prefixes are not allowed in value or pivot columns of an UNPIVOT operator. |
276 | 16 | Pseudocolumns are not allowed as value or pivot columns of an UNPIVOT operator. |
277 | 16 | The column «%.*ls» is specified multiple times in the column list of the UNPIVOT operator. |
278 | 16 | The text, ntext, and image data types cannot be used in a GROUP BY clause. |
279 | 16 | The text, ntext, and image data types are invalid in this subquery or aggregate expression. |
280 | 16 | Only text, ntext, and image columns are valid with the TEXTPTR function. |
281 | 16 | <Style number> is not a valid style number when converting from %ls to a character string. |
282 | 10 | The ‘%.*ls’ procedure attempted to return a status of NULL, which is not allowed. A status of 0 will be returned instead. |
283 | 16 | READTEXT cannot be used on inserted or deleted tables within an INSTEAD OF trigger. |
284 | 16 | Rules cannot be bound to text, ntext, or image data types. |
285 | 16 | The READTEXT, WRITETEXT, and UPDATETEXT statements cannot be used with views or functions. |
286 | 16 | The logical tables INSERTED and DELETED cannot be updated. |
287 | 16 | The %ls statement is not allowed within a trigger. |
288 | 16 | The PATINDEX function operates on char, nchar, varchar, nvarchar, text, and ntext data types only. |
290 | 16 | Invalid EXECUTE statement using object «%ls», method «%ls». |
291 | 16 | CAST or CONVERT: invalid attributes specified for type ‘%.*ls’ |
292 | 16 | There is insufficient result space to convert a smallmoney value to varchar/nvarchar. |
293 | 16 | Cannot convert char value to smallmoney. The char value has incorrect syntax. |
294 | 16 | The conversion from char data type to smallmoney data type resulted in a smallmoney overflow error. |
295 | 16 | Syntax error converting character string to smalldatetime data type. |
296 | 16 | The conversion of char data type to smalldatetime data type resulted in an out-of-range smalldatetime value. |
297 | 16 | The user does not have permission to perform this action. |
298 | 16 | The conversion from datetime data type to smalldatetime data type resulted in a smalldatetime overflow error. |
299 | 16 | The DATEADD function was called with bad type %ls. |
300 | 14 | %ls permission was denied on object ‘%.*ls’, database ‘%.*ls’. |
301 | 16 | Query contains an outer-join request that is not permitted. |
302 | 16 | The newsequentialid() built-in function can only be used in a DEFAULT expression for a column of type ‘uniqueidentifier’ in a CREATE TABLE or ALTER TABLE statement. It cannot be combined with other operators to form a complex scalar expression. |
303 | 16 | The table ‘%.*ls’ is an inner member of an outer-join clause. This is not allowed if the table also participates in a regular join clause. |
304 | 16 | ‘%d’ is out of range for index option ‘%.*ls’. See sp_configure option ‘%ls’ for valid values. |
305 | 16 | The XML data type cannot be compared or sorted, except when using the IS NULL operator. |
306 | 16 | The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator. |
307 | 16 | Index ID %d on table ‘%.*ls’ (specified in the FROM clause) does not exist. |
308 | 16 | Index ‘%.*ls’ on table ‘%.*ls’ (specified in the FROM clause) does not exist. |
309 | 16 | Cannot use index «%.*ls» on table «%.*ls» in a hint. XML indexes are not allowed in hints. |
310 | 16 | The value <MAXRECURSION value> specified for the MAXRECURSION option exceeds the allowed maximum of %d. |
311 | 16 | Cannot use text, ntext, or image columns in the ‘inserted’ and ‘deleted’ tables. |
312 | 16 | Cannot reference text, ntext, or image columns in a filter stored procedure. |
313 | 16 | An insufficient number of arguments were supplied for the procedure or function %.*ls. |
314 | 16 | Cannot use GROUP BY ALL with the special tables INSERTED or DELETED. |
315 | 16 | Index «%.*ls» on table «%.*ls» (specified in the FROM clause) is disabled or resides in a filegroup which is not online. |
316 | 16 | The index ID %d on table «%.*ls» (specified in the FROM clause) is disabled or resides in a filegroup which is not online. |
317 | 16 | Table-valued function ‘<Function Name>’ cannot have a column alias. |
318 | 16 | The table (and its columns) returned by a table-valued method need to be aliased. |
319 | 16 | Incorrect syntax near the keyword ‘with’. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon. |
320 | 16 | The compile-time variable value for ‘%.*ls’ in the OPTIMIZE FOR clause must be a literal. |
321 | 15 | %.*ls is not a recognized table hints option. If it is intended as a parameter to a table-valued function or to the CHANGETABLE function, ensure that your database compatibility mode is set to 90. |
322 | 16 | The variable «%.*ls» is specified in the OPTIMIZE FOR clause, but is not used in the query. |
323 | 16 | The ‘COMPUTE’ clause is not allowed in a statement containing an INTERSECT or EXCEPT operator. |
324 | 15 | The ‘ALL’ version of the %.*ls operator is not supported. |
325 | 15 | Incorrect syntax near ‘%.*ls’. You may need to set the compatibility level of the current database to a higher value to enable this feature. See help for the SET COMPATIBILITY_LEVEL option of ALTER DATABASE. |
326 | 16 | Multi-part identifier ‘%.*ls’ is ambiguous. Both columns ‘%.*ls’ and ‘%.*ls’ exist. |
327 | 16 | Function call ‘%.*ls’ is ambiguous: both a user-defined function and a method call with this name exist. |
328 | 16 | A cursor plan could not be generated for the given statement because the textptr() function was used on a LOB column from one of the base tables. |
329 | 16 | Each GROUP BY expression must contain at least one column reference. |
330 | 15 | The target ‘<Object Name>’ of the OUTPUT INTO clause cannot be a view or common table expression. |
331 | 15 | The target table ‘<Table Name>’ of the OUTPUT INTO clause cannot have any enabled triggers. |
332 | 15 | The target table ‘<Table Name>’ of the OUTPUT INTO clause cannot be on either side of a (primary key, foreign key) relationship. Found reference constraint ‘<Primary Key or Foreign Key Constraint Name>’. |
333 | 15 | The target table ‘<Table Name>’ of the OUTPUT INTO clause cannot have any enabled check constraints or any enabled rules. Found check constraint or rule ‘<CHECK Constraint Name>’. |
334 | 15 | The target table ‘<Table Name>’ of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause. |
335 | 16 | Function call cannot be used to match a target table in the FROM clause of a DELETE or UPDATE statement. Use function name ‘%.*ls’ without parameters instead. |
336 | 15 | Incorrect syntax near ‘%.*ls’. If this is intended to be a common table expression, you need to explicitly terminate the previous statement with a semi-colon. |
337 | 10 | Warning: the floating point value ‘%.*ls’ is too small. It will be interpreted as 0. |
338 | 16 | READEXT, WRITETEXT, and UPDATETEXT statements cannot be used with views, remote tables, and inserted or deleted tables inside triggers. |
339 | 16 | DEFAULT or NULL are not allowed as explicit identity values. |
340 | 16 | Cannot create the trigger «%.*ls» on view «%.*ls». AFTER triggers cannot be created on views. |
341 | 16 | Replication filter procedures may not contain columns of large object, large value, XML or CLR type. |
342 | 16 | Column «%.*ls» is not allowed in this context, and the user-defined function or aggregate «%.*ls» could not be found. |
343 | 16 | Unknown object type ‘%.*ls’ used in a CREATE, DROP, or ALTER statement. |
344 | 16 | Remote function reference ‘%.*ls’ is not allowed, and the column name ‘%.*ls’ could not be found or is ambiguous. |
345 | 16 | Function ‘%.*ls’ is not allowed in the OUTPUT clause, because it performs user or system data access, or is assumed to perform this access. A function is assumed by default to perform data access if it is not schemabound. |
346 | 15 | The parameter «<Parameter Name>» can not be declared READONLY since it is not a table-valued parameter. |
347 | 16 | The table-valued parameter «%.*ls» cannot be declared as an OUTPUT parameter. |
348 | 16 | The table variable «%.*ls» can not be passed to a stored procedure with the OUTPUT option. |
349 | 16 | The procedure «%.*ls» has no parameter named «%.*ls». |
350 | 16 | The column «%.*ls» does not have a valid data type. A column cannot be of a user-defined table type. |
351 | 16 | Column, parameter, or variable %.*ls. : Cannot find data type %.*ls. |
352 | 15 | The table-valued parameter «%.*ls» must be declared with the READONLY option. |
353 | 16 | Function ‘%.*ls’ is not allowed in the %S_MSG clause when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement. This is because the function performs user or system data access, or is assumed to perform this access. By default, a function is assumed to perform data access if it is not schema-bound. |
354 | 15 | The target ‘%.*ls’ of the INSERT statement cannot be a view or common table expression when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement. |
355 | 15 | The target table ‘<Table Name>’ of the INSERT statement cannot have any enabled triggers when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement. |
356 | 15 | The target table ‘%.*ls’ of the INSERT statement cannot be on either side of a (primary key, foreign key) relationship when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement. Found reference constraint ‘%ls’. |
357 | 15 | The target table ‘%.*ls’ of the INSERT statement cannot have any enabled rules when the FROM clause contains a nested INSERT, UPDATE, DELETE, or MERGE statement. Found rule ‘%ls’. |
358 | 15 | The target table ‘%.*ls’ of the MERGE statement cannot have any enabled rules. Found rule ‘%ls’. |
359 | 15 | The target ‘%.*ls’ of an OUTPUT INTO clause has an index with the ignore_dup_key option and cannot be used when an OUTPUT clause is also used. |
360 | 15 | The target column list of an INSERT, UPDATE, or MERGE statement cannot contain both a sparse column and the column set that contains the sparse column. Rewrite the statement to include either the sparse column or the column set, but not both. |
361 | 16 | The number of target columns that are specified in an INSERT, UPDATE, or MERGE statement exceeds the maximum of %d. This total number includes identity, timestamp, and columns that have default values. To correct this error, change the query to target a sparse column set instead of single sparse columns. |
362 | 16 | The query processor could not produce a query plan because the name ‘%.*ls’ in the FORCESEEK hint on table or view ‘<Object Name>’ did not match the key column names of the index ‘<Index Name>’. |
363 | 16 | The query processor could not produce a query plan because the FORCESEEK hint on table or view ‘<Object Name>’ cannot be used with the %S_MSG specified by index ‘%.*ls’. |
364 | 16 | The query processor could not produce a query plan because the FORCESEEK hint on view ‘<View Name>’ is used without a NOEXPAND hint. Resubmit the query with the NOEXPAND hint or remove the FORCESEEK hint on the view. |
365 | 16 | The query processor could not produce a query plan because the FORCESEEK hint on table or view ‘<Object Name>’ specified more seek columns than the number of key columns in index ‘%.*ls’. |
366 | 16 | The query processor could not produce a query plan because the FORCESEEK hint on table or view ‘<Object Name>’ cannot be used with the column store index ‘%.*ls’. |
401 | 16 | Unimplemented statement or expression %ls. |
402 | 16 | The data types %s and %s are incompatible in the %s operator. |
403 | 16 | Invalid operator for data type. Operator equals add, type equals text. |
404 | 16 | The column reference «inserted.%.*ls» is not allowed because it refers to a base table that is not being modified in this statement. |
405 | 16 | A remote table cannot be used as a DML target in a statement which includes an OUTPUT clause or a nested DML statement. |
406 | 16 | %ls cannot be used in the PIVOT operator because it is not invariant to NULLs. |
407 | 16 | Internal error. The string routine in file %hs, line %d failed with HRESULT 0x%x. |
408 | 16 | A constant expression was encountered in the ORDER BY list, position %i. |
409 | 16 | The %ls operation cannot take a %ls data type as an argument. |
410 | 20 | COMPUTE clause #%d ‘BY’ expression #%d is not in the order by list. |
411 | 16 | COMPUTE clause #%d, aggregate expression #%d is not in the select list. |
412 | 16 | The column «%.*ls» is not updatable because it is derived or constant. |
413 | 16 | Correlated parameters or sub-queries are not supported by the inline function «%.*ls». |
414 | 16 | UPDATE is not allowed because the statement updates view «%.*ls» which participates in a join and has an INSTEAD OF UPDATE trigger. |
415 | 16 | DELETE is not allowed because the statement updates view «%.*ls» which participates in a join and has an INSTEAD OF DELETE trigger. |
416 | 16 | The service queue «%.*ls» cannot be directly updated. |
417 | 16 | TOP is not allowed in an UPDATE or DELETE statement against a partitioned view. |
418 | 16 | Objects exposing CLR type columns are not allowed in distributed queries. Use a pass-through query to access the remote object ‘%.*ls’. |
420 | 16 | The text, ntext, and image data types cannot be used in an ORDER BY clause. |
421 | 16 | The text/ntext/image data type cannot be selected as DISTINCT because it is not comparable. |
422 | 16 | Common table expression defined but not used. |
423 | 16 | Xml data type methods are not supported in check constraints. Create a scalar user-defined function to wrap the method invocation. The error occurred at table «%.*ls». |
424 | 16 | Xml data type methods are not supported in computed column definitions of table variables and return tables of table-valued functions. The error occurred at column «%.*ls», table «%.*ls», in the %ls statement. |
425 | 16 | Data type %ls of receiving variable is not equal to the data type %ls of column ‘%.*ls’. |
426 | 16 | The length %d of the receiving variable is less than the length %d of the column ‘%.*ls’. |
427 | 20 | Could not load sysprocedures entries for constraint ID %d in database ID %d. |
428 | 20 | Could not find row in sysconstraints for constraint ID %d in database ID %d. |
429 | 20 | Could not find new constraint ID %d in sysconstraints, database ID %d, at compile time. |
430 | 20 | Could not resolve table name for object ID %d, database ID %d, when compiling foreign key. |
431 | 19 | Could not bind foreign key constraint. Too many tables involved in the query. |
432 | 16 | Xml data type methods are not supported in check constraints anymore. Please drop the constraint or create a scalar user-defined function to wrap the method invocation. The error occurred at table «%.*ls». |
433 | 20 | Could not find CHECK constraint for ‘%.*ls’, although the table is flagged as having one. |
434 | 16 | Function ‘%ls’ is not allowed in the OUTPUT clause. |
435 | 16 | Xml data type methods are not supported in computed column definitions. Create a scalar user-defined function to wrap the method invocation. The error occurred at column «%.*ls», table «%.*ls», in the %ls statement. |
436 | 20 | Could not open referenced table ID %d in database ID %d. |
437 | 20 | Could not resolve the referenced column name in table ID %d. |
438 | 20 | Could not resolve the referencing column name in table ID %d. |
439 | 20 | Could not find FOREIGN KEY constraints for table ‘%.*ls’ in database ID %d although the table is flagged as having them. |
440 | 16 | Internal query compilation error. The stack overflow could not be handled. |
441 | 16 | Cannot use the ‘%ls’ function on a remote data source. |
442 | 16 | The NEST argument must be a column reference. Expressions are not allowed. |
443 | 16 | Invalid use of ‘getdate’ within a function. Invalid use of ‘INSERT’ within a function. Invalid use of ‘UPDATE’ within a function. |
444 | 16 | Select statements included within a function cannot return data to a client. |
445 | 16 | COLLATE clause cannot be used on expressions containing a COLLATE clause. |
446 | 16 | Cannot resolve collation conflict for %ls operation. |
447 | 16 | Expression type %ls is invalid for COLLATE clause. |
448 | 16 | Invalid collation ‘%.*ls’. |
449 | 16 | Collation conflict caused by collate clauses with different collation ‘%.*ls’ and ‘%.*ls’. |
450 | 16 | Code page translations are not supported for the text data type. From: %d To: %d. |
451 | 16 | Cannot resolve collation conflict for column %d in %ls statement. |
452 | 16 | COLLATE clause cannot be used on user-defined data types. |
453 | 16 | Collation ‘%.*ls’ is supported on Unicode data types only and cannot be set at the database or server level. |
454 | 16 | The UNNEST argument must be a nested table column. |
455 | 16 | The last statement included within a function must be a return statement. |
456 | 16 | Implicit conversion of %ls value to %ls cannot be performed because the resulting collation is unresolved due to collation conflict. |
457 | 16 | Implicit conversion of %ls value to %ls cannot be performed because the collation of the value is unresolved due to a collation conflict. |
458 | 16 | Cannot create the SELECT INTO target table «%.*ls» because the xml column «%.*ls» is typed with a schema collection «%.*ls» from database «%.*ls». Xml columns cannot refer to schemata across databases. |
459 | 16 | Collation ‘%.*ls’ is supported on Unicode data types only and cannot be applied to char, varchar or text data types. |
460 | 16 | DISTINCT operator is not allowed in the recursive part of a recursive common table expression ‘<Common Table Expression Name>’. |
461 | 16 | TOP operator is not allowed in the recursive part of a recursive common table expression ‘<Common Table Expression Name>’. |
462 | 16 | Outer join is not allowed in the recursive part of a recursive common table expression ‘<Common Table Expression Name>’. |
463 | 16 | Functions with parameters are not allowed in the recursive part of a recursive common table expression ‘%.*ls’. |
464 | 16 | Functions with side effects are not allowed in the recursive part of a recursive common table expression ‘%.*ls’. |
465 | 16 | Recursive references are not allowed in subqueries. |
466 | 16 | UNION operator is not allowed in the recursive part of a recursive common table expression ‘%.*ls’. |
467 | 16 | GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression ‘<CTE Name>’. |
468 | 16 | Cannot resolve the collation conflict between «%.*ls» and «%.*ls» in the %ls operation. |
469 | 16 | An explicit column list must be specified for target table ‘%.*ls’ when table hint KEEPIDENTITY is used and the table contains an identity column. |
470 | 16 | The synonym «<Synonym Name>» referenced synonym «<Synonym Name>». Synonym chaining is not allowed. |
471 | 16 | Only one of the three options, SINGLE_BLOB, SINGLE_CLOB or SINGLE_NCLOB, can be specified. |
472 | 16 | Either a format file or one of the three options SINGLE_BLOB, SINGLE_CLOB, or SINGLE_NCLOB must be specified. |
473 | 16 | The incorrect value «%.*ls» is supplied in the PIVOT operator. |
474 | 16 | Unable to load the computed column definitions for table «%.*ls». |
475 | 16 | Invalid SAMPLE clause. Only table names in the FROM clause of SELECT, UPDATE, and DELETE queries may be sampled. |
476 | 16 | Invalid PERCENT tablesample size «<sample_number>» for table «<Table Name>». The PERCENT tablesample size must be between 0 and 100. |
477 | 16 | Invalid ROWS value or REPEATABLE seed in the TABLESAMPLE clause for table «<Table Name>». The value or seed must be an integer. |
478 | 16 | The TABLESAMPLE clause cannot be used in a view definition or inline table function definition. |
479 | 16 | Invalid ROWS value or REPEATABLE seed «%I64d» in the TABLESAMPLE clause for table «%.*ls». The value or seed must be greater than 0. |
480 | 16 | The TABLESAMPLE clause cannot be used with the table function «%.*ls». |
481 | 16 | The TABLESAMPLE clause cannot be used with the linked server table «%.*ls». |
482 | 16 | Non-constant or invalid expression is in the TABLESAMPLE or the REPEATABLE clause. |
483 | 16 | The OUTPUT clause cannot be used in an INSERT…EXEC statement. |
484 | 16 | Cannot declare more than %d local variables. |
485 | 16 | Views and inline functions cannot return xml columns that are typed with a schema collection registered in a database other than current. Column «%.*ls» is typed with the schema collection «%.*ls», which is registered in database «%.*ls». |
486 | 16 | %.*ls does not allow specifying a schema name as a prefix to the assembly name. |
487 | 16 | An invalid option was specified for the statement «%.*ls». |
488 | 16 | %s columns must be comparable. The type of column «%.*ls» is «%s», which is not comparable. |
489 | 16 | The OUTPUT clause cannot be specified because the target view «%.*ls» is a partitioned view. |
490 | 16 | The resync functionality is temporarily disabled. |
491 | 16 | A correlation name must be specified for the bulk rowset in the from clause. |
492 | 16 | Duplicate column names are not allowed in result sets obtained through OPENQUERY and OPENROWSET. The column name «%.*ls» is a duplicate. |
493 | 16 | The column ‘%.*ls’ that was returned from the nodes() method cannot be used directly. It can only be used with one of the four XML data type methods, exist(), nodes(), query(), and value(), or in IS NULL and IS NOT NULL checks. |
494 | 16 | The TABLESAMPLE clause can only be used with local tables. |
495 | 16 | The return table column «%.*ls» is not the same type as the type it was created with. Drop and recreate the module using a two-part name for the type, or use sp_refreshsqlmodule to refresh its parameters metadata. |
496 | 16 | The parameter «%.*ls» is not the same type as the type it was created with. Drop and recreate the module using a two-part name for the type, or use sp_refreshsqlmodule to refresh its parameters metadata. |
497 | 16 | Variables are not allowed in the TABLESAMPLE or REPEATABLE clauses. |
498 | 16 | Invalid value in the TABLESAMPLE or the REPEATABLE clause. |
499 | 16 | Invalid parameter for the getchecksum function. |
500 | 16 | Trying to pass a table-valued parameter with %d column(s) where the corresponding user-defined table type requires %d column(s). |
List of error messages between 1 and 999 in SQL Server 2017.
These error messages are all available by querying the sys.messages
catalog view on the master
database.