Введение в триггеры mysql
Содержание:
Шаг 1 — Создание тестовой базы данных
На этом этапе вы создадите тестовую клиентскую базу данных пользователя с несколькими таблицами для демонстрации работы триггеров MySQL.
Более подробно о работе MySQL можно прочитать в инструкции Запросы в MySQL.
Вначале войдите на сервер MySQL как root:
По запросу введите свой root пароль MySQL и нажмите для продолжения. Когда вы увидите , выполните следующую команду, чтобы создать базу данных :
Далее переходите к с помощью:
Начинайте с создания таблицы . В этой таблице будут храниться записи клиентов, включая , и . Будет два типа клиентов: и .
Теперь, добавьте несколько записей в таблицу . Для этого выполните следующие команды одну за другой:
После выполнения каждой команды вы увидите следующий вывод:
Чтобы убедиться, что тестовые записи были успешно вставлены, выполните команду :
Затем создайте другую таблицу для хранения соответствующей информации об учетной записи клиентов. Таблица будет содержать поля и .
Запустите следующую команду:
Далее создайте таблицу . В этой таблице будут храниться данные о продажах, имеющих отношение к разным клиентам в столбце :
Вы сможете добавить тестовые данные в колонку на следующих этапах во время тестирования триггеров. Далее создайте таблицу для регистрации обновлений, внесенных в таблицу при имплементации триггера в шаге 5:
Имея базу данных и четыре таблицы, теперь вы можете перейти к работе с различными триггерами MySQL в вашей базе данных.
Classes of SQL Server Triggers
There are two classes of triggers in SQL Server:
- DDL (Data Definition Language) triggers. This class of triggers fires upon
events that change the structure (like creating, modifying or dropping a table),
or in certain server related events like security changes or statistics update
events. - DML (Data Modification Language) triggers. This is the most used class of
triggers. In this case the firing event is a data modification statement; it
could be an insert, update or delete statement either on a table or a view.
Additionally, DML triggers have different types:
- FOR or AFTER : These types of triggers are executed
after the firing statement ends (either an insert, update or delete). - INSTEAD OF : Contrary to the FOR (AFTER) type, the
INSTEAD OF triggers executes instead of the firing statement. In other words,
this type of trigger replaces the firing statement. This is very useful in cases
where you need to have cross database referential integrity.
5 последних уроков рубрики «Разное»
-
Выбрать хороший хостинг для своего сайта достаточно сложная задача. Особенно сейчас, когда на рынке услуг хостинга действует несколько сотен игроков с очень привлекательными предложениями. Хорошим вариантом является лидер рейтинга Хостинг Ниндзя — Макхост.
-
Как разместить свой сайт на хостинге? Правильно выбранный хороший хостинг — это будущее Ваших сайтов
Проект готов, Все проверено на локальном сервере OpenServer и можно переносить сайт на хостинг. Вот только какую компанию выбрать? Предлагаю рассмотреть хостинг fornex.com. Отличное место для твоего проекта с перспективами бурного роста.
-
Создание вебсайта — процесс трудоёмкий, требующий слаженного взаимодействия между заказчиком и исполнителем, а также между всеми членами коллектива, вовлечёнными в проект. И в этом очень хорошее подспорье окажет онлайн платформа Wrike.
-
Подборка из нескольких десятков ресурсов для создания мокапов и прототипов.
Атрибутные функции
Oracle предоставляет набор функций (определенных в пакете ) для получения информации о причине запуска триггера DDL и других связанных с ним параметрах (например, имя удаляемой таблицы). Перечень этих атрибутных функций приведен в табл. 2, а примеры их использования — в следующих разделах.
Таблица 2. События триггеров DDL и атрибутные функции
| Функция | Что возвращает |
| ORA_CLIENT_IP_ADDRESS | IP-адрес клиента |
| ORA_DATABASE_NAME | Имя базы данных |
| ORA_DES_ENCRYPTED_PASSWORD | Пароль текущего пользователя, зашифрованный с использованием алгоритма DES |
| ORA_DICT_OBJ_NAME | Имя объекта базы данных, связанного с командой DDL, которая вызвала запуск триггера |
| ORA_DICT_OBJ_NAME_LIST | Количество обработанных командой объектов. В параметре возвращается полный список этих объектов в виде коллекции типа |
| ORA_DICT_OBJ_OWNER | Имя владельца объекта базы данных, связанного с командой DDL, которая вызвала запуск триггера |
| ORA_DICT_OBJ_OWNER_LIST | Количество обработанных командой объектов. В параметре возвращается полный список имен этих объектов в виде коллекции типа |
| ORA_DICT_OBJ_TYPE | Тип объекта базы данных, связанного с командой DDL, вызвавшей запуск триггера (например, или ) |
| ORA_GRANTEE | Количество пользователей, получивших привилегии. В аргументе содержится полный список этих пользователей в виде коллекции типа |
| ORA_INSTANCE_NUM | Номер экземпляра базы данных |
| ORA_IS_ALTER_COLUMN | , если изменяется столбец, заданный параметром ; в противном случае |
| ORA_IS_CREATING_NESTED_TABLE | , если создается вложенная таблица; в противном случае |
| ORA_IS_DROP_COLUMN | , если удаляется столбец, заданный параметром_ в противном случае |
| ORA_LOGIN_USER | Имя пользователя, для которого запущен триггер |
| ORA_PARTITION_POS | Позиция команды для корректной вставки секции |
| ORA_PRIVILEGE_LIST | Количество предоставленных или отмененных привилегий. В аргументе содержится полный список привилегий в виде коллекции типа |
| ORA_REVOKEE | Количество пользователей, лишенных привилегий. В аргументе содержится полный список этих пользователей в виде коллекции типа |
| ORA_SQL_TXT | Количество строк в команде SQL, которая вызвала запуск триггера. Аргумент возвращает каждую строку команды в виде аргумента типа |
| ORA_SYSEVENT | Тип события, вызвавшего запуск триггера DDL (например, , или ) |
| ORA_WITH_GRANT_OPTION | , если привилегии предоставлены конструкцией ; в противном случае |
Об атрибутных функциях необходимо дополнительно сказать следующее:
Тип данных 0RA_NAME_LIST_T определен в пакете DBMS_STANDARD так:
Иными словами, это вложенная таблица строк, каждая из которых может содержать до 64 символов.
- События триггеров DDL и атрибутные функции также определены в пакете . Для каждой из функций этого пакета Oracle создает независимую функцию, добавляя к ее имени префикс 0RA_, для чего при создании базы данных выполняется сценарий В некоторых версиях Oracle этот сценарий содержит ошибки, из-за которых независимые функции не видны или не выполняются. Если вы сомневаетесь в правильности определения этих элементов, попросите администратора базы данных проверить сценарий и внести необходимые исправления.
- Представление словаря данных не обновляется до срабатывания обоих триггеров и . Иначе говоря, вы не сможете использовать эти функции для реализации системы контроля версий «до и после», построенной исключительно в границах базы данных и основанной на триггерах.
Атрибуты системных триггеров
| Атрибут | Возвращаемое значение и тип |
|---|---|
| ora_client_ip_address | Varchar2 ip-адрес клиентаПример: |
| ora_database_name | Varchar2(50) имя базы данныхПример: |
| ora_des_encrypted_password | Varchar2 зашифрованный по стандарту DES пароль пользователя, который создается или изменяетсяПример: |
| ora_dict_obj_name | Varchar2(30) имя объекта, над которым совершается операция DDLПример: |
| ora_dict_obj_name_list ( name_list OUT ora_name_list_t ) |
Pls_integer количество изменненых командой объектов Name_list – список измененных командой объектовПример: |
| ora_dict_obj_owner | Varchar2(30) владелец объекта, над которым совершается операция DDLПример: |
| ora_dict_obj_owner_list ( owner_list OUT ora_name_list_t ) |
Pls_integer количество владельцев измененных командой объектов Owner_list – список владельцев изменных командой объектовПример: |
| ora_dict_obj_type | Varchar2(20) тип объекта, над которым совершается операция ddlПример: |
| ora_grantee ( user_list OUT ora_name_list_t ) |
Pls_integer количество пользователей, участвующих в операции grant User_list – список этих пользователейПример: |
| ora_instance_num | Number номер инстансаПример: |
| ora_is_alter_column ( column_name IN VARCHAR2 ) |
Boolean True, если указанное поле было изменено операцией alter. Иначе falseПример: |
| ora_is_creating_nested_table | Boolean true, если текущее событие – это создание nested table. Иначе falseПример: |
| ora_is_drop_column ( column_name IN VARCHAR2 ) |
Boolean true, если указанное поле удалено. Иначе falseПример: |
| ora_is_servererror ( error_number IN VARCHAR2 ) |
Boolean true, если сгенерированно исключение с номером error_number. Иначе falseПример: |
| ora_login_user | Varchar2(30) имя текущего пользователяПример: |
| ora_partition_pos | Pls_integer в instead of trigger для create table позиция в тексте sql команды, где может быть вставлена конструкция partitionПример: |
| ora_privilege_list ( privilege_list OUT ora_name_list_t ) |
Pls_integer количество привилегий, участвующее в операции grant или revoke Privilege_list – список этих привилегийПример: |
| ora_revokee ( user_list OUT ora_name_list_t ) |
Pls_integer количество пользователей, участвующих в операции revoke User_list – список этих пользователейПример: |
| ora_server_error ( position IN PLS_INTEGER ) |
Number код ошибки в указанной позиции error stack, где 1 – это вершина стекаПример: |
| ora_server_error_depth | Pls_integer количество сообщений об ошибка в error stackПример: |
| ora_server_error_msg ( position IN PLS_INTEGER ) |
Varchar2 сообщение об ошибке в указанном месте error stackПример: |
| ora_server_error_num_params ( position IN PLS_INTEGER ) |
Pls_integer количество замещенных строк (с помощью формата %s) в указанной позиции error stackПример: |
| ora_server_error_param ( position IN PLS_INTEGER, param IN PLS_INTEGER ) |
Varchar2 замещенный текст в сообщении об ошибке в указанной позиции error stack (возвращается param по счету замещенный текст)Пример: |
| ora_sql_txt ( sql_text OUT ora_name_list_t ) |
Pls_integer количество элементов в pl/sql коллекции sql_text. Сам параметр sql_text возвращает текст команды, на которую сработал триггерПример: |
| ora_sysevent | Varchar2(20) название команды, на которую срабатывает триггерПример: |
| ora_with_grant_option | Boolean true, если привилегии выдаются with grant option. Иначе false.Пример: |
| ora_space_error_info ( error_number OUT NUMBER, error_type OUT VARCHAR2, object_owner OUT VARCHAR2, table_space_name OUT VARCHAR2, object_name OUT VARCHAR2, sub_object_name OUT VARCHAR2 ) |
Boolean true, если ошибка возникает из-за нехватки места. В выходных параметрах информация об объекте.Пример: |
SQL Server Trigger Usage Scenarios
There are two clear scenarios when triggers are the best choice: auditing and
enforcing business rules. By using a trigger, you can keep track of the changes on
a given table by writing a log record with information about who made the change
and what was changed in the table.
Maybe you think that you can do the same in the application with a stored procedure
that handles data modification like inserts and updates. You can use a stored procedure,
but in such a case you will not be able to log the changes that were made directly
to the database from outside the application.
The same happens when you want to enforce business rules with a stored procedure.
If someone modifies the data on the base table from outside the application you
can have a problem because the data consistency cannot be guaranteed. To avoid this
issue, you would make sure the stored procedure was the only way to access the
table.
Триггеры DDL и области их применения
Ранее мы рассмотрели триггеры DML, которые задают действие, предпринимаемое сервером при изменении таблицы инструкциями INSERT, UPDATE или DELETE. Компонент Database Engine также позволяет определять триггеры для инструкций DDL, таких как CREATE DATABASE, DROP TABLE и ALTER TABLE. Триггеры для инструкций DDL имеют следующий синтаксис:
Соглашения по синтаксису
Как можно видеть по их синтаксису, триггеры DDL создаются таким же способом, как и триггеры DML. А для изменения и удаления этих триггеров используются те же инструкции ALTER TRIGGER и DROP TRIGGER, что и для триггеров DML. Поэтому в этом разделе рассматриваются только те параметры инструкции CREATE TRIGGER, которые новые для синтаксиса триггеров DDL.
Первым делом при определении триггера DDL нужно указать его область действия. Предложение DATABASE указывает в качестве области действия триггера DDL текущую базу данных, а предложение ALL SERVER — текущий сервер.
После указания области действия триггера DDL нужно в ответ на выполнение одной или нескольких инструкций DDL указать способ запуска триггера. В параметре event_type указывается инструкция DDL, выполнение которой запускает триггер, а в альтернативном параметре event_group указывается группа событий языка Transact-SQL. Триггер DDL запускается после выполнения любого события языка Transact-SQL, указанного в параметре event_group. Ключевое слово LOGON указывает триггер входа.
Кроме сходства триггеров DML и DDL, между ними также есть несколько различий. Основным различием между этими двумя видами триггеров является то, что для триггера DDL можно задать в качестве его области действия всю базу данных или даже весь сервер, а не всего лишь отдельный объект. Кроме этого, триггеры DDL не поддерживают триггеров INSTEAD OF. Как вы, возможно, уже догадались, для триггеров DDL не требуются таблицы inserted и deleted, поскольку эти триггеры не изменяют содержимого таблиц.
В следующих подразделах подробно рассматриваются две формы триггеров DDL: триггеры уровня базы данных и триггеры уровня сервера.
Триггеры DDL уровня базы данных
В примере ниже показано, как можно реализовать триггер DDL, чья область действия распространяется на текущую базу данных:
Триггер в этом примере предотвращает удаление любого триггера для базы данных SampleDb любым пользователем. Предложение DATABASE указывает, что триггер trigger_PreventDrop является триггером уровня базы данных. Ключевое слово DROP_TRIGGER указывает предопределенный тип события, запрещающий удаление любого триггера.
Триггеры DDL уровня сервера
Триггеры уровня сервера реагируют на серверные события. Триггер уровня сервера создается посредством использования предложения ALL SERVER в инструкции CREATE TRIGGER. В зависимости от выполняемого триггером действия, существует два разных типа триггеров уровня сервера: обычные триггеры DDL и триггеры входа. Запуск обычных триггеров DDL основан на событиях инструкций DDL, а запуск триггеров входа — на событиях входа.
В примере ниже демонстрируется создание триггера уровня сервера, который является триггером входа:
Здесь сначала создается имя входа SQL Server loginTest, которое потом используется в триггере уровня сервера. По этой причине, для этого имени входа требуется разрешение VIEW SERVER STATE, которое и предоставляется ему посредством инструкции GRANT. После этого создается триггер trigger_ConnectionLimit. Этот триггер является триггером входа, что указывается ключевым словом LOGON.
С помощью представления sys.dm_exec_sessions выполняется проверка, был ли уже установлен сеанс с использованием имени входа loginTest. Если сеанс уже был установлен, выполняется инструкция ROLLBACK. Таким образом имя входа loginTest может одновременно установить только один сеанс.
What is a SQL Server Trigger?
A SQL Server trigger is a piece of procedural code, like a stored procedure which
is only executed when a given event happens. There are different types of events
that can fire a trigger. Just to name you a few, the insertion of rows in a table,
a change in a table structure and even a user logging into a SQL Server instance.
There are three main characteristics that make triggers different than stored
procedures:
- Triggers cannot be manually executed by the user.
- There is no chance for triggers to receive parameters.
- You cannot commit or rollback a transaction inside a trigger.
The fact that it’s impossible to use parameters on triggers is not a limitation
to receive information from the firing event. As you will see further on, there
are alternatives to obtain information about the firing event.
3.4.7. Дополнительно о триггерах
Вы можете использовать триггеры для обеспечения комплексной целостности ссылок с помощью:
- Выполнения действий или каскадного обновления или удаления. Целостность ссылок может отличаться при использовании ограничений FOREIGN KEY и REFERENCE в операторе CREATE TABLE. Но триггер выгоден для гарантирования необходимых действий, когда должны быть произведены каскадные удаления или обновления, потому что триггеры более мощные. Если ограничение существует для таблицы с триггером, оно проверяется до выполнения триггера. Если ограничение нарушено, то триггер не работает. Если ограничение не сработает, то с помощью триггера можно реализовать более сложные проверки, которые уж точно будут гарантировать, что данные не нарушат целостность и пользователь внесет только те данные, которые разрешены;
- Вы должны учитывать, что в таблицу может вставляться сразу несколько строк. Вы должны учитывать это при написании триггеров, как мы это делали при создании примеров с использованием INSTEAD OF;
- Ограничения, правила и значения по умолчанию могут генерировать только стандартные системные ошибки. Если вам нужны собственные сообщения, вы должны использовать триггеры.
При разработке триггеров, вы должны учитывать, что таблицы могут иметь несколько триггеров для любого действия. Каждый триггер может быть объявлен для нескольких или одного действия. Например, в следующем примере обрабатывается два события INSERT и UPDATE:
CREATE TRIGGER iu_tbPeoples ON dbo.tbPeoples FOR INSERT, UPDATE AS Действие
Если на одно действие назначено несколько триггеров, чтобы не конфликтовали имена можно к имени добавить слово, которое будет описывать выполняемые действия или назначение.
Владелец таблицы может указывать первый и последний триггеры. Когда несколько триггеров помещены на таблицу, владелец может использовать процедуру sp_settriggerorder (о хранимых системных таблицах мы будем говорить в следующей главе) для указания первого выполняемого триггера и последнего. Порядок остальных триггеров не может устанавливаться.
Владельцы таблицы не могут создавать триггеры на просмотрщики и временные таблицы. Однако триггеры могут ссылаться на просмотрщики и временные таблицы.
Триггеры не должны возвращать результирующих наборов, хотя не запрещается что-то выводить на печать с помощью оператора PRINT, но вы должны отдавать себе отчет, что пользователь увидит это только при откате транзакции. Таким образом, можно сообщить только об ошибке, но не об удачном выполнении, хотя, в большинстве случаем этого нам достаточно.
Теперь поговорим о производительности триггеров. Они выполняются достаточно быстро, потому что:
- расположены на сервере и не требуют для своего выполнения сетевых обращений, если только в самом коде триггера нет обращений по сети;
- таблицы Insert и Deleted расположены в кэше, поэтому обращение к ним происходит достаточно быстро, если только они не содержат множества строк и обращения к таблицам не содержат сложных связей с другими таблицами.
Используйте триггеры только там, где это необходимо. Старайтесь возложить основные операции по обеспечению целостности на ограничения. Если нельзя найти другого выхода, то для повышения производительности сервера делайте объявление операторов триггеров простыми, на сколько это возможно. Так как триггер является частью транзакции, блокировки сохраняются, пока транзакция не завершится, поэтому здесь скорость обработки наиболее важна.
Составные триггеры
По мере создания триггеров, содержащих все больший объем бизнес-логики, становится трудно следить за тем, какие триггеры связаны с теми или иными правилами и как триггеры взаимодействуют друг с другом. В предыдущем разделе было показано, как три типа команд DML (вставка, обновление, удаление) объединяются в одном триггере, но разве не удобно было бы разместить триггеры строк и команд вместе в одном объекте кода? В появилась возможность использования составных триггеров для решения этой задачи. Следующий простой пример демонстрирует этот синтаксис:
Сходство с пакетами
Составные триггеры похожи на пакеты , не правда ли? Весь сопутствующий код и логика находятся в одном месте, что упрощает его отладку и изменение. Рассмотрим синтаксис более подробно.
Самое очевидное изменение — конструкция , сообщающая Oracle, что триггер содержит несколько триггеров, которые должны срабатывать вместе. Следующее (и пожалуй, самое долгожданное) изменение встречается в строке 5: глобальная переменная! Наконец-то глобальные переменные могут определяться вместе с кодом, который с ними работает, — специальные пакеты для них больше не нужны:
В остальном синтаксис составных триггеров очень похож на синтаксис автономных триггеров, но не так гибок:
- — код этого раздела выполняется до команды , как и в случае с автономным триггером .
- — код этого раздела выполняется перед обработкой каждой строки командой .
- — код этого раздела выполняется после обработки каждой строки командой .
- — код этого раздела выполняется после команды , как и в случае с автономным триггером .
Правила автономных триггеров также применимы и к составным триггерам — например, значения записей ( и ) не могут изменяться в триггерах уровня команд.
Различия с пакетами
Итак, составные триггеры похожи на пакеты PL/SQL, но означает ли это, что они так же работают? Нет — они работают лучше! Рассмотрим следующий пример:
Обратите внимание: при выполнении второй команды для глобальной переменной снова выводится 1. Это связано с тем, что область действия составного триггера ограничивается командой , которая его инициирует
После завершения этой команды составной триггер и его значения, хранящиеся в памяти, перестают существовать. Это обстоятельство упрощает логику.
Дополнительным преимуществом ограниченной области действия является упрощенная обработка ошибок. Чтобы продемонстрировать это обстоятельство, я определяю в таблице первичный ключ для последующего нарушения:
Теперь вставим одну запись:
Пока без сюрпризов. Но следующая команда выдает ошибку из-за нарушения нового первичного ключа:
Следующая команда также снова выдает ошибку первичного ключа. Но в этом как раз ничего примечательного нет — примечательно то, что глобальная переменная была снова инициализирована значением 1 без написания дополнительного кода. Команда завершилась, составной триггер вышел из области действия, и со следующей командой все начинается заново:
Теперь мне не нужно включать дополнительную обработку ошибок или пакеты только для сброса значений при возникновении исключения.
с составными триггерами
Составные триггеры также могут использоваться с синтаксисом :
Результат:
Конкретные триггеры, находящиеся внутри составного триггера, не могут определяться как срабатывающие после каких-либо автономных или составных триггеров.
Если автономный триггер определяется как следующий за составным триггером, который не содержит триггер, срабатывающий по той же команде или строке, секция просто игнорируется.
Управление приложениями PL/SQL… 2182 просмотров Rasen Fasenger Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL… 4432 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Тип данных RAW в PL/SQL 3606 просмотров Doctor Thu, 12 Jul 2018, 08:41:33
Символьные функции и аргументы… 7479 просмотров Анатолий Wed, 23 May 2018, 18:54:01
Author: Doctor
Другие статьи автора:
3.4.5. Как работают триггеры?
В данной главе мы более глубоко рассмотрим, как работают различные типы триггеров. Для этого мы напишем множество примеров, максимально приближенных к реальности, а заодно получим хорошую практику программирование на языке Transact-SQL и создания триггеров.
Триггер INSERT
Что происходит, когда срабатывает триггер добавления записей? Давайте рассмотрим выполняемые сервером шаги:
- Пользователем выполняется оператор INSERT для добавления записей;
- Сервер сохраняет информацию о запросе в журнале транзакций;
- Вызывается триггер;
- Подтверждение изменений и физическое изменение данных.
Во время вызова триггера, физического изменения в базе еще не произошло. В теле триггера вы можете увидеть добавляемые записи в виде таблицы inserted. Нет, такой таблицы в базе данных не существует, inserted – это логическая таблица, которая содержит копию строк, которые должны быть вставлены в таблицу. Если быть точнее, она содержит журнал активности оператора INSERT. Вы можете использовать данные из этой таблицы для определения вставляемых данных. Строки из таблицы inserted всегда дублируют одну или несколько строк таблицы триггера.
Вся активность по изменению данных записываются в журнал, но информация в журнале транзакций не читаема. Однако таблица inserted позволяет вам ссылаться и определить изменения.
Таблица inserted всегда содержит такую же структуру, что и у таблицы, на которую установлен триггер.
Давайте запретим с помощью триггера добавление записей, в которых имя работника равно Вася. Пример такого триггера можно увидеть в листинге 3.4.
Листинг 3.4. Использование таблицы inserted
CREATE TRIGGER i_tbPeoples ON dbo.tbPeoples FOR INSERT AS DECLARE @Name varchar(50) SELECT @Name=vcName FROM inserted IF @Name='ВАСЯ' BEGIN PRINT 'ОШИБКА' ROLLBACK TRANSACTION END
В данном примере мы создаем триггер на добавление записей. Внутри триггера мы объявляем переменную @Name типа varchar длиной в 50 символов. В эту переменную мы сохраняем содержимое поля «vcName» таблицы inserted. Далее проверяем, если имя равно Вася, то сообщаем об ошибке и откатываем транзакцию. Иначе, строка будет удачно добавлена.
Давайте для закрепления материала, напишем триггер, который запретит нулевые значения для поля «vcName». Код такого триггера можно увидеть в листинге 3.5.
Листинг 3.5. Запрет нулевых значений в поле с помощью триггера
CREATE TRIGGER i_tbPeoples ON dbo.tbPeoples
FOR INSERT
AS
IF EXISTS (SELECT *
FROM inserted
WHERE vcName is NULL)
BEGIN
PRINT 'ОШИБКА, вы должны заполнить поле vcName'
ROLLBACK TRANSACTION
END
В этом примере мы проверяем, если в таблице inserted есть записи с нулевым значением поля «vcName», то откатываем попытку добавления.