Как найти триггер sql

I created a trigger for a table in SQL Server and it works for me.

My problem is: How do find it and modify it?

I use this query to find my triggers:

select * from sys.triggers

This find all triggers, but how to open it and change the triggers?

JeanValjean's user avatar

JeanValjean

17k23 gold badges113 silver badges157 bronze badges

asked Sep 10, 2012 at 7:17

ar.gorgin's user avatar

You can do this simply with SSMS. Just go to your table name and expand the Triggers node to view a list of triggers associated with that table. Right click to modify your trigger.
enter image description here

Jørgen R's user avatar

Jørgen R

10.5k7 gold badges42 silver badges59 bronze badges

answered Sep 10, 2012 at 7:28

Buzz's user avatar

BuzzBuzz

5,8704 gold badges33 silver badges47 bronze badges

1

select so.name, text
from sysobjects so, syscomments sc
where type = 'TR'
and so.id = sc.id
and text like '%YourTableName%'

This way you can list out all the triggers associated with the given table.

Maslow's user avatar

Maslow

18.4k20 gold badges105 silver badges192 bronze badges

answered Sep 10, 2012 at 7:29

Jigar Pandya's user avatar

Jigar PandyaJigar Pandya

5,9722 gold badges27 silver badges45 bronze badges

3

This might be useful

SELECT 
 t.name AS TableName,
 tr.name AS TriggerName  
FROM sys.triggers tr
INNER JOIN sys.tables t ON t.object_id = tr.parent_id
WHERE 
t.name in ('TABLE_NAME(S)_GOES_HERE');

This way you just have to plugin the name of tables and the query will fetch all the triggers you need

answered Jul 8, 2015 at 12:34

Saurabh's user avatar

SaurabhSaurabh

3373 silver badges9 bronze badges

select m.definition from sys.all_sql_modules m inner join  sys.triggers t
on m.object_id = t.object_id 

Here just copy the definition and alter the trigger.

Else you can just goto SSMS and Expand the your DB and under Programmability expand Database Triggeres then right click on the specific trigger and click modify there also you can change.

answered Sep 10, 2012 at 7:25

AnandPhadke's user avatar

AnandPhadkeAnandPhadke

13k5 gold badges25 silver badges33 bronze badges

use sp_helptrigger to find the triggerlist for the associated tables

answered Sep 21, 2015 at 10:03

Padhu's user avatar

PadhuPadhu

973 silver badges10 bronze badges

find triggers on table:

select so.name, text
from sysobjects so, syscomments sc
where type = 'TR'
and so.id = sc.id
and text like '%TableName%'

and you can find store procedure which has reference of table:

SELECT Name
FROM sys.procedures
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%yourtablename%'

thaavik's user avatar

thaavik

3,2472 gold badges18 silver badges25 bronze badges

answered Aug 31, 2017 at 13:16

Rahul mishra's user avatar

select   B.name 
from     sys.objects    A
join     sys.triggers   B
on     A.object_id    =    B.parent_id
where    A.name    ='Table_name' /*Table Name*/

answered Jun 9, 2021 at 6:31

user8804754's user avatar

1

Go through

Need to list all triggers in SQL Server database with table name and table’s schema

This URL have set of queries by which you can get the list of triggers associated with particular table.

I believe you are working in sqlserver following are the steps to get modify triggers

To modify a trigger

  1. Expand a server group, and then expand a server.

  2. Expand Databases, expand the database in which the table containing
    the trigger belongs, and then click Tables.

  3. In the details pane, right-click the table on which the trigger
    exists, point to All Tasks, and then click Manage Triggers.

  4. In Name, select the name of the trigger.

  5. Change the text of the trigger in the Text field as necessary. Press
    CTRL+TAB to indent the text of a SQL Server Enterprise Manager
    trigger.

  6. To check the syntax of the trigger, click Check Syntax.

Community's user avatar

answered Sep 10, 2012 at 7:29

Manish Prajapati's user avatar

With this query you can find all Trigger in all tables and all views.

    ;WITH
        TableTrigger
        AS
        (
            Select 
                Object_Kind = 'Table',
                Sys.Tables.Name As TableOrView_Name , 
                Sys.Tables.Object_Id As Table_Object_Id ,
                Sys.Triggers.Name As Trigger_Name, 
                Sys.Triggers.Object_Id As Trigger_Object_Id 
            From Sys.Tables 
            INNER Join Sys.Triggers On ( Sys.Triggers.Parent_id = Sys.Tables.Object_Id )
            Where ( Sys.Tables.Is_MS_Shipped = 0 )
        ),
        ViewTrigger
        AS
        (
            Select 
                Object_Kind = 'View',
                Sys.Views.Name As TableOrView_Name , 
                Sys.Views.Object_Id As TableOrView_Object_Id ,
                Sys.Triggers.Name As Trigger_Name, 
                Sys.Triggers.Object_Id As Trigger_Object_Id 
            From Sys.Views 
            INNER Join Sys.Triggers On ( Sys.Triggers.Parent_id = Sys.Views.Object_Id )
            Where ( Sys.Views.Is_MS_Shipped = 0 )
        ),
        AllObject
        AS
        (
            SELECT * FROM TableTrigger

            Union ALL

            SELECT * FROM ViewTrigger
        )


    Select 
        * 
    From AllObject
    Order By Object_Kind, Table_Object_Id 

answered Feb 20, 2017 at 21:25

Ardalan Shahgholi's user avatar

Ardalan ShahgholiArdalan Shahgholi

11.8k20 gold badges107 silver badges144 bronze badges

 select o1.name as trigger_name,o2.name as table_name from sys.objects o1 
 join sys.objects o2 on 
 o1.parent_object_id=o2.object_id     
 where o1.type='TR' 
 and o2.name='my_table'
 
  

answered Feb 15, 2021 at 23:31

YakovGdl35's user avatar

YakovGdl35YakovGdl35

3212 silver badges4 bronze badges

You Can View All trigger related to your database by below query

select * from sys.triggers

And for open trigger you can use below syntax

sp_helptext 'dbo.trg_InsertIntoUserTable'

Sterling Archer's user avatar

answered Mar 28, 2019 at 2:11

Anuj Kumar's user avatar

Anuj KumarAnuj Kumar

291 silver badge6 bronze badges

Much simple query below

select (select [name] from  sys.tables where [object_id] = tr.parent_id ) as TableName ,*  from sys.triggers tr

Soner Gönül's user avatar

Soner Gönül

96.7k102 gold badges205 silver badges360 bronze badges

answered Apr 17, 2015 at 5:58

dilipkumar katre's user avatar

select * from information_schema.TRIGGERS;

answered Feb 6, 2018 at 8:44

Mrinal's user avatar

MrinalMrinal

1155 bronze badges

select t.name as TriggerName,m.definition,is_disabled 
from sys.all_sql_modules m 
inner join  
sys.triggers t
on m.object_id = t.object_id 
inner join sys.objects o
on o.object_id = t.parent_id
Where o.name = 'YourTableName'

This will give you all triggers on a Specified Table

answered Jul 18, 2018 at 7:31

ℛⱥℐℰşℎ's user avatar

ℛⱥℐℰşℎℛⱥℐℰşℎ

3602 silver badges10 bronze badges

Try to Use:

select * from sys.objects where type='tr' and name like '%_Insert%'

answered Mar 28, 2019 at 9:41

Fezal halai's user avatar

Fezal halaiFezal halai

7467 silver badges14 bronze badges

you can open your trigger with
sp_helptext yourtriggername

answered Jul 18, 2019 at 5:45

danish's user avatar

To expand a little on the previous answers, in all the recent versions of SQL Server you can right click on a trigger and choose: Script Trigger as… ALTER To… "New Query Editor Window"

This will open an SQL script with the details of the trigger, if you read the code you will notice that it includes the ALTER syntax: ALTER TRIGGER [dbo].triggername ...

This means you can edit the SQL and press Execute to alter the trigger – this will overwrite the previous definition.

If the triggers have been built using automated tools, you may find duplicate code in the trigger definition which you will want to remove.

It is worth trying to Execute the script first before trying to edit anything, that will tell you if the trigger definition is valid. If a table or column has been renamed, things can get out of sync.

Similarly to Delete/Drop a trigger completely select: Script Trigger as… DROP To… "New Query Editor Window" and then execute it.

In an earlier article, we have seen a simple tip for finding triggers which are modified during a given date range. Now we will see how to find the triggers which are created against a table or multiple tables with similar partial name or a schema. Let us see them one by one.

It is easy to find triggers created against a table. All you have to do is Expand the table in the SSMS or Azure Data Studio‘s left panel and then expand the Triggers folder.

Finding triggers against a table

Listing triggers on tables having similar partial name

However, listing all the triggers created against tables which have similar partial names is not straightforward. You have to use the sys table sys.triggers for finding the triggers. Here is the script:

SELECT
    Name as 'Trigger', 
    OBJECT_NAME(parent_id) AS 'Table'
FROM
   sys.triggers
WHERE
   OBJECT_NAME(parent_id) LIKE '%_A'
GO

Finding Triggers For Tables

Listing triggers on tables under a schema

Likewise, here is the script to list all the triggers against tables within a schema. In this illustration, Purchasing is the name of the schema.

SELECT
    Name as 'Trigger', 
    OBJECT_SCHEMA_NAME(parent_id) AS 'Schema', 
    OBJECT_NAME(parent_id) AS 'Table'
FROM
   sys.triggers
WHERE
   OBJECT_SCHEMA_NAME(parent_id) = 'Purchasing'
GO

Finding Triggers For Tables Under a Schema

Reference

  • More about sys.triggers at Microsoft Docs.

В мире стартапов с открытыми исходными кодами и разработкой полного стека (типа Django, Rails, Javascript, PHP, MySQL, Postgres…) очень популярны ORM, а средства типа триггеров SQL не так востребованы.

Но все же триггеры SQL сохраняют свое значение. Когда я работал над нестандартной ERP-системой, триггеры оказались неоценимым инструментом. При построении сильно ориентированного на данные ПО, особенно с данными в финансовой сфере, где точность является главным требованием, вы с большей вероятностью увидите, что данные обрабатываются непосредственно на более низком уровне.

В этой статье я поделюсь информацией о том, как эффективно использовать триггеры SQL.

Содержание

  1. Что такое триггер?
  2. Как создать триггер SQL – синтаксис PostgreSQL
  3. Пример триггера в PostgreSQL #1: создание таймера
  4. Пример триггера в PostgreSQL #2: создание таблицы аудита
  5. Дополнительные соображения о триггерах

Что такое триггер?

Триггеры SQL, также называемые триггерами баз данных, позволяют вам сказать движку SQL (например PostgreSQL) выполнить часть кода при наступлении некоторого события, или даже перед наступлением события.

В PostgreSQL вы описываете исполняемый код посредством создания функции, которая возвращает значение типа trigger. В некоторых других движках, например, MySQL блок кода является частью триггера, и находится внутри него.

Прежде чем рассматривать различные типы событий и конкретный синтаксис создания триггера, обсудим, зачем бы вам понадобилось использовать триггеры баз данных.

Преимущества использования триггеров SQL

Поддержание целостности данных

Триггеры баз данных могут найти множество применений и являются прекрасным инструментом для обеспечения строгой целостности данных. Альтернативные решения типа хуков модели Django могут сбоить, если вы имеете другие серверы приложений или пользователей с доступом к базе данных, которые не знают конкретной бизнес-логики, закодированной в вашем приложении.

Разделение бизнес-логики

Размещение критичной бизнес-логики в коде приложения также представляет проблему, когда бизнес-логика обновляется. Если вашим бизнес-требованием являлось умножение входящих номеров на 10, а теперь вы захотели умножать это число на 20, изменение логики в SQL гарантировало бы, что каждые данные, начиная точно с момента развертывания, будут обрабатываться новой логикой.

Сервер SQL действует как единственная точка истины. Если логика внедрена на множестве серверов приложений, вы не сможете ожидать определенного изменения в поведении, выполненного чисто.

Атомарные транзакции

Естественная атомарность является еще одной желательной особенностью, присущей триггерам. Поскольку событие и триггерная функция являются частью одной атомарной транзакции, вы знаете с абсолютной определенностью, что триггер сработает, если возникнет событие. Они как единое целое в идеальном браке SQL.

Как создать триггер SQL: синтаксис PostgreSQL

Вот составляющие создания триггера для вашей базы данных:

  1. Тип события триггера
  2. До или после события
  3. Воздействие триггера

Типы событий триггера

Триггеры баз данных будут мониторить конкретные события для таблицы. Вот некоторые примеры различных событий, которые могут активировать триггер:

Триггер базы данных допускает также перечисление более одного из этих событий.

Если одним из перечисленных событий является UPDATE, вы можете передать список столбцов, которые должны активировать триггер. Если вы не включаете этот список, обновление любого столбца будет его активировать.

Триггер BEFORE (до) или AFTER (после)

Триггер может выполняться либо до, либо после события.

Если вы хотите заблокировать событие типа INSERT, вы захотите выполнять действие до (BEFORE). Если вы хотите быть уверенным, что событие действительно произойдет, идеальный вариант – после (AFTER).

Воздействие триггера

Триггер может выполняться либо на строку, либо на оператор. Скажем, вы выполняете один оператор UPDATE, который изменяет 5 строк в таблице.

Если вы укажете в триггере FOR EACH ROW, тогда триггер выполнится 5 раз. Если вы укажете FOR EACH STATEMENT, тогда он выполнится только раз.

И, конечно, мы не можем забыть о фактическом коде, который выполняется при срабатывании триггера. В PostgreSQL он помещается в функцию и отделен от триггера. Разделение триггера и кода, который он выполняет, создает более чистый код и позволяет нескольким триггерам выполнять один и тот же код.

Пример триггера #1: создание таймера

Фиксация времени прихода и ухода с работы сотрудников, и вычисление общего отработанного времени. Давайте создадим пример таймера и посмотрим, каким образом мы можем использовать триггеры для предотвращения ввода сотрудниками неверных данных.

Настройка схемы базы данных

Структура схемы предполагает каждый вход и выход отдельными событиями. Каждое событие – это строка в таблице time_punch. Как альтернативу вы можете также сделать каждую “рабочую смену” сотрудника событием и хранить время как входа, так и выхода в одной строке.

В следующей статье я глубже погружусь в разработку схемы базы данных.

Для нашего примера я уже разработал схему таблиц. Нижеприведенный код создает таблицы employee и time_punch и вставляет некоторые данные по времени прохода для нового сотрудника Bear.

create table employee ( id serial primary key, username varchar );
create table time_punch (
id serial primary key,
employee_id int not null references employee(id),
is_out_punch boolean not null default false,
punch_time timestamp not null default now()
);
insert into employee (username) values ('Bear');
insert into time_punch (employee_id, is_out_punch, punch_time)
values
(1, false, '2020-01-01 10:00:00'),
(1, true, '2020-01-01 11:30:00');

Bear зашел в 10:00 и вышел в 11:30 (длинный рабочий день). Давайте напишем запрос SQL для вычисления рабочего времени Bear.

Остановитесь и подумайте, как бы вы решили эту задачу при данной схеме и с помощью одного SQL.

Использование SQL для вычисления рабочего времени

Решение, которое я предлагаю, ищет на каждый “выход” соответствующий ему “вход”.

select tp1.punch_time - tp2.punch_time as time_worked
from time_punch tp1
join time_punch tp2
on tp2.id = (
select tps.id
from time_punch tps
where tps.id < tp1.id
and tps.employee_id = tp1.employee_id
and not tps.is_out_punch
order by tps.id desc limit 1
)
where tp1.employee_id = 1 and tp1.is_out_punch;

time_worked
2
-------------
3
01:30:00 (1 row)

В этом запросе я выбираю все выходы, затем я соединяю их с наиболее близким “входом”. Беру разность временных меток и получаю количество часов, которое отработал Bear в каждой смене!

Одна из проблем в этой схеме состоит в том, что возможно вставить несколько “входов” или “выходов” подряд. С созданным запросом это приведет к неоднозначности, которая может привести к неточным расчетам и зарплате сотрудников – тбольше или меньше, чем они должны были бы получить.

Пример триггера INSERT BEFORE: сохранение целостности данных

Нам требуется то, что не позволит нарушить шаблон вход/выход. К сожалению, ограничения check только отслеживают вставляемую или обновляемую строку и не могут учитывать данные из других строк.

Это идеальная ситуация для использования триггера баз данных!

Давайте создадим триггер для предотвращения события INSERT, которое нарушает наш шаблон. Сначала мы создадим “триггерную функцию”. Эта функция есть то, что будет выполнять триггер при наступлении события.

Триггерная функция создается как обычная функция PostgreSQL за тем исключением, что возвращает триггер.

create or replace function fn_check_time_punch() returns trigger as $psql$
begin
if new.is_out_punch = (
select tps.is_out_punch
from time_punch tps
where tps.employee_id = new.employee_id
order by tps.id desc limit 1
) then
return null;
end if;
return new;
end;
$psql$ language plpgsql;

Ключевое слово new представляет значения вставляемой строки. Это также объект, который вы можете вернуть, чтобы позволить продолжиться вставке. Напротив, возвращение null остановит вставку.

Этот запрос сначала находит в time_punch предыдущее значение и гарантирует, что это значение входа/выхода не совпадает с вставляемым значением. Если значения совпадают, то триггер возвращает null, и time_punch не записывается. В противном случае, триггер возвращает new и оператор insert продолжается.

Теперь мы привяжем функцию в качестве триггера к таблице time_punch. BEFORE здесь ключевой момент. Если мы выполним этот триггер как триггер AFTER, он будет выполнен слишком поздно, чтобы остановить вставку.

create trigger check_time_punch before insert on time_punch
for each row execute procedure fn_check_time_punch();

Давайте попробуем вставить еще один “выход”:

insert into time_punch (employee_id, is_out_punch, punch_time)
values
(1, true, '2020-01-01 13:00:00');

Output: INSERT 0 0

Как можно видеть по выводу, триггер предотвратил вставку двух последовательных выходов для одного и того же сотрудника.

Можно также вызвать исключение из триггера с тем, чтобы ваше приложение (или лицо, выполняющее запрос SQL) получило уведомление об отказе вместо 0 как числа вставленных строк.

Пример триггера в PostgreSQL #2: создание таблицы аудита

Аккуратное сохранение данных о нахождении сотрудников критично для бизнеса. Данные подобного типа часто непосредственно отражаются на зарплате и, с другой стороны, на заработках компании.

Ввиду важности этих данных, пусть компания хочет воссоздавать в хронологии состояние таблицы на случай обнаружения нарушений.

Таблица аудита выполняет эту роль, отслеживая каждое изменение основной таблицы. Когда в главной таблице обновляется строка, в таблицу аудита вставляется строка в ее предыдущем состоянии.

Я буду использовать нашу таблицу time_punch для демонстрации создания и автоматического обновления таблицы аудита с помощью триггеров.

Создание таблицы аудита

create table time_punch_audit (
id serial primary key,
change_time timestamp not null default now(),
change_employee_id int not null references employee(id),
time_punch_id int not null references time_punch(id),
punch_time timestamp not null
);

В эту таблицу записывается:

  • Время обновления прохождения.
  • Сотрудник, который выполнил обновление.
  • ID прохода, который был изменен.
  • Время прохода до того, как было сделано обновление.

Прежде чем создавать триггер, сначала нам нужно добавить столбец change_employee_id в таблицу time_punch. Тогда триггер будет знать, какой сотрудник сделал каждое изменение в таблице time_punch.

alter table time_punch 
add column change_employee_id int null references employee(id);

(Как альтернативное решение без добавления каких-либо столбцов в time_punch, можно аннулировать права update на эту таблицу и заставить пользователей базы данных использовать пользовательскую функцию типа update_time_punch(id, change_user_id, …))

После того, как произойдет обновление таблицы time_punch, выполнится этот триггер и запишет OLD (старое) значение времени прохода в нашу таблицу аудита.

create or replace function fn_change_time_punch_audit() returns trigger as $psql$
begin
insert into time_punch_audit (change_time, change_employee_id, time_punch_id, punch_time)
values
(now(), new.change_employee_id, new.id, old.punch_time);
return new;
end;
$psql$ language plpgsql;

create trigger change_time_punch_audit after update on time_punch
for each row execute procedure fn_change_time_punch_audit();

Функция NOW() возвращает текущую дату и время с точки зрения сервера SQL. Если бы это было привязано к настоящему приложению, вы, вероятно, захотели бы передавать точное время, когда пользователь фактически сделал запрос, чтобы избежать расхождения из-за задержки.

Для триггера на обновление объект NEW представляет те значения, которые будут содержаться
в строке при успешном обновлении. Вы можете использовать триггер для “перехвата” вставки или обновления простым присвоением своих собственных значений в объект NEW. Объект OLD содержит значения строки до обновления.

Проверим, работает ли это! Я добавил второго пользователя с именем Daniel, который будет редактором времени прохода Bear.

select punch_time
from time_punch
where id=2;

punch_time
---------------------
2020-01-01 11:30:00
(1 row)

Я собираюсь выполнить дважды нижеприведенный запрос для имитации 2 редакций, которые увеличивают время на 5 минут.

update time_punch 
set punch_time = punch_time + interval '5 minute', change_employee_id = 2
where id = 2;

А вот таблица аудита, отражающая прошлые времена прохода:

Дополнительные сообщажения относительно триггеров

Вот несколько вещей, связанные с триггерами, которые следует иметь в виду:

  1. Обслуживание триггеров с течением времени.
  2. Связанная логика триггера.
  3. Опыт разработчиков.

Обслуживание триггеров с течением времени

Бизнес-логика в коде приложения документируется естественным образом, т.к. она меняется со временем, с помощью git или другой системы управления исходниками. Разработчику легко увидеть логику в базовом коде и сделать быструю журнализацию git, а также посмотреть список изменений.

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

Связанная логика триггера

Триггеры также могут запускать другие триггеры, быстро усложняя результаты казалось бы невинных INSERT или UPDATE. Этот риск также может привести к побочным эффектам кода приложения.

Опыт разработчиков

Знания триггеров так же довольно низки в среде некоторых разработчиков, поэтому введение их увеличивает вложения в обучение, которое потребуется новым разработчикам для успешной работы над проектом.

Изначально SQL может показаться неуклюжим и неудобным языком для изучения, поскольку многие из шаблонов, которые вы изучаете для построения запроса, «вывернуты наизнанку» по сравнению с тем, как вы извлекаете данные на процедурном языке.

Я надеюсь, что у вас появится возможность изучить и реализовать одну из самых увлекательных и интригующих функций SQL!

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