Введение в триггеры 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», то откатываем попытку добавления.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *