Форум программистов, компьютерный форум, киберфорум
Microsoft SQL Server
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.69/29: Рейтинг темы: голосов - 29, средняя оценка - 4.69
1 / 1 / 0
Регистрация: 18.03.2013
Сообщений: 45

Триггер INSTEAD OF

19.03.2013, 17:09. Показов 5574. Ответов 25
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте! Нужна помощь...
Есть две таблицы:
Группы(НомерГруппы, Факультет, КолвоСтудентов)
Студенты(Фио,НомерГруппы,.....)

Хочу реализовать триггер INSTEAD OF UPDATE чтобы при обновлении группы у студента, данные изменения отразились на количестве групп. Из той которой перевелся в таблице КолвоСтудентов - 1, в ту которую перевелся соответственно КолвоСтудентов + 1

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TRIGGER InsteadUpdate ON dbo.Студенты
INSTEAD OF UPDATE AS
BEGIN
DECLARE @insgroup CHAR(10)
DECLARE @updgroup CHAR(10)
SELECT @insgroup = НомерГруппы FROM inserted
SELECT @updgroup = НомерГруппы FROM deleted
IF EXISTS ( SELECT 
            a.НомерГруппы FROM dbo.Группы a INNER JOIN inserted b
            ON a.НомерГруппы = b.НомерГруппы
            AND a.НомерГруппы = @insgroup)
            BEGIN
            UPDATE dbo.Группы SET КолвоСтудентов = КолвоСтудентов + 1
            WHERE НомерГруппы = @insgroup
            UPDATE dbo.Группы SET КолвоСтудентов = КолвоСтудентов - 1
            WHERE НомерГруппы = @updgroup
            END
            ELSE
            RAISERROR(N'Такой группы не существует',10,10)
 
END
Ошибка с IF до BEGIN первого...всё никак не могу условие правильное сделать!
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
19.03.2013, 17:09
Ответы с готовыми решениями:

Триггер для добавления к строке название таблицы, в которой содержится триггер
Есть таблицы База_Практик. В неё добавляю предприятие, и автоматически нужно добавить это предприятие с именем таблицы База практик в...

Триггер для добавления к строке название таблицы, в которой содержится триггер
Есть таблицы База_Практик. В неё добавляю предприятие, и автоматически нужно добавить это предприятие с именем таблицы База практик в...

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

25
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,272
19.03.2013, 17:32
Во-первых, почему INSTEAD OF UPDATE?
Во-вторых, как собираетесь присваивать скалярным переменным
сразу несколько значений, если проапдейтили больше одной записи одним UPDATE?
В-третьих, скобки кто считать будет?

И вообще, всё написано очень странно.
0
1 / 1 / 0
Регистрация: 18.03.2013
Сообщений: 45
19.03.2013, 17:37  [ТС]
Цитата Сообщение от iap Посмотреть сообщение
Во-первых, почему INSTEAD OF UPDATE?
Во-вторых, как собираетесь присваивать скалярным переменным
сразу несколько значений, если проапдейтили больше одной записи одним UPDATE?
В-третьих, скобки кто считать будет?

И вообще, всё написано очень странно.
Первый вопрос непонятен...

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CREATE TRIGGER InsteadUpdate  ON dbo.Студенты
INSTEAD OF UPDATE AS
BEGIN
DECLARE @insgroup CHAR(10)
DECLARE @updgroup CHAR(10)
DECLARE @delname CHAR(20)
SELECT @insgroup = НомерГруппы FROM inserted
SELECT @updgroup = НомерГруппы FROM deleted
SELECT @delname = ФИО FROM deleted
IF EXISTS ( SELECT 
            a.НомерГруппы FROM dbo.Группы a INNER JOIN inserted b
            ON a.НомерГруппы = b.НомерГруппы
            AND a.НомерГруппы = @insgroup)
            BEGIN
            UPDATE dbo.Студенты SET НомерГруппы = @insgroup
            WHERE dbo.Студенты.ФИО = @delname
            UPDATE dbo.Группы SET КолвоСтудентов = КолвоСтудентов + 1
            WHERE НомерГруппы = @insgroup
            UPDATE dbo.Группы SET КолвоСтудентов = КолвоСтудентов - 1
            WHERE НомерГруппы = @updgroup
            END
            ELSE
            RAISERROR(N'Такой группы не существует',10,10)
 
END
Вот исправил, вроде работает! Я исправил ошибки о которых Вы сообщили, iap?
0
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,272
19.03.2013, 20:23
Первый вопрос - почему INSTEAD OF UPDATE, а не AFTER (FOR) UPDATE? Обоснование можно увидеть?

Второе - по моему глубокому убеждению в триггере не должно быть скалярных переменных.
Для меня их наличие - признак говнокода.
Ну, разве что переменная для хранения сообщения об ошибке для финального RAISERROR()...
0
1 / 1 / 0
Регистрация: 18.03.2013
Сообщений: 45
19.03.2013, 21:47  [ТС]
Цитата Сообщение от iap Посмотреть сообщение
Первый вопрос - почему INSTEAD OF UPDATE, а не AFTER (FOR) UPDATE? Обоснование можно увидеть?

Второе - по моему глубокому убеждению в триггере не должно быть скалярных переменных.
Для меня их наличие - признак говнокода.
Ну, разве что переменная для хранения сообщения об ошибке для финального RAISERROR()...
Я новичок в этом деле! Неделю наверно как начал...
Так вот: AFTER UPDATE- я так понимаю это триггер, выполняющий действия уже после того как был совершен UPDATE. У меня же проверяется, а можно ли обновить сперва.
А почему это плохой признак? Интересно...рад любым советам

И еще вопрос. Когда тольок начинал делать, установил каскадное обновление и удаление между этими двумя таблицами. Как это можно отменить?
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 00:20
примерно так:
T-SQL
1
2
3
create table Группы(НомерГруппы int, КолвоСтудентов int)
create table Студенты(id int identity primary key, Фио varchar(50), НомерГруппы int)
go
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
create trigger Студенты_изменения on Студенты
after insert, update, delete as
-- Удаление студентов или перевод из группы
update g set g.КолвоСтудентов-=q.qty
   from Группы g
   join (select НомерГруппы, COUNT(*) qty from deleted group by НомерГруппы) q on q.НомерГруппы=g.НомерГруппы;
-- Добавление студентов или перевод в группу
merge Группы g 
   using (select НомерГруппы,count(*)qty from inserted group by НомерГруппы)q
   on  q.НомерГруппы=g.НомерГруппы
   when matched then update set g.КолвоСтудентов+=q.qty
   when not matched then insert (НомерГруппы, КолвоСтудентов) values (q.НомерГруппы, q.qty);
go
Понаблюдать за работой триггера можно в режиме пошаговой отладки:
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
insert Студенты values ('Студ1', 1)
select * from Группы
select * from Студенты
 
insert Студенты values ('Студ2', 2),('Студ3', 1)
select * from Группы
select * from Студенты
 
update Студенты set НомерГруппы=3
select * from Группы
select * from Студенты
 
delete Студенты where id<3
select * from Группы
select * from Студенты
0
 Аватар для _katon_
414 / 265 / 25
Регистрация: 03.10.2011
Сообщений: 1,094
20.03.2013, 00:28
Эм... я тоже очень интересуюсь почему переменная в триггере - говнокод?
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 00:41
триггер работает не с одиночной записью, а со всеми, подходящими по фильтру запроса. Соответственно запихивать таблицу в скаляр ошибочно.
0
 Аватар для _katon_
414 / 265 / 25
Регистрация: 03.10.2011
Сообщений: 1,094
20.03.2013, 01:18
Цитата Сообщение от cygapb-007 Посмотреть сообщение
Соответственно запихивать таблицу в скаляр ошибочно.
не совсем понимаю как в скаляр (я так понимаю скалярная переменная) можно засунуть таблицу (я так понимаю табличный тип данных).
Цитата Сообщение от iap Посмотреть сообщение
по моему глубокому убеждению в триггере не должно быть скалярных переменных.
Тут вообще речь о скалярных переменных. Я не утверждаю что это не гавнокод, но как то хотелось бы выслушать причину. А ели причины нет, то значит можно "бомбить" DECLARE в триггере без остановки...
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 01:25
Цитата Сообщение от _katon_ Посмотреть сообщение
не совсем понимаю как в скаляр (я так понимаю скалярная переменная) можно засунуть таблицу (я так понимаю табличный тип данных).
Поясните, пожалуйста, вот этот фрагмент: что в нем делается?
Например, при выполнении запроса update студенты set НомерГруппы=35 where НомерГруппы=15 ?
Или еще круче - update студенты set НомерГруппы+=20
SQL
1
2
SELECT @insgroup = НомерГруппы FROM inserted
SELECT @updgroup = НомерГруппы FROM deleted
0
 Аватар для _katon_
414 / 265 / 25
Регистрация: 03.10.2011
Сообщений: 1,094
20.03.2013, 01:36
Предположительно строковым переменным @insgroup, @updgroup задается значение поля "НомерГруппы" из табличек inserted и deleted соответственно. И в чем некашерность? То, что в данном случае это лишено смысла не означает, что в других случаях это неприменимо или вредно (никто же не может похвастаться, что видел все возможные кодирования всех возможных триггеров). Я для себя хочу установить почему это гавнокод, т.е. из каких соображений.
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 01:55
Цитата Сообщение от _katon_ Посмотреть сообщение
Предположительно строковым переменным @insgroup, @updgroup задается значение поля "НомерГруппы" из табличек inserted и deleted соответственно. И в чем некашерность? То, что в данном случае это лишено смысла не означает, что в других случаях это неприменимо или вредно (никто же не может похвастаться, что видел все возможные кодирования всех возможных триггеров). Я для себя хочу установить почему это гавнокод, т.е. из каких соображений.
Не совсем точный ответ. Это как раз попытка втиснуть в скалярную переменную сразу все значения столбца "НомерГруппы"

В случае первого запроса у всех студентов из группы 15 меняется код группы на 35, соответственно в inserted куча строк типа Фамилия-35, а в deleted столько же строк (сколько всего было студентов в гр.15) типа Фамилия-15. В итоге после фичи типа "set @var+=field from table" в переменных будут (предположительно, не проверял) значения из какой-то одной строки этих таблиц. Для первого запроса это не критично, потому что у всех "было 15 стало 35".

Во втором запросе есть разные значения в номерах групп - и все они (кроме одного) будут проигнорированы триггером. Более того, нет гарантии, что номера групп, полученные из inserted и из deleted будут относиться к одной операции замены, а не образуется, например, пара "было 75 стало 35" (имеется в виду переход на следующий курс и соответственно "повышение" номера группы для всех студентов).
1
 Аватар для _katon_
414 / 265 / 25
Регистрация: 03.10.2011
Сообщений: 1,094
20.03.2013, 02:06
Верно, потереял я концентрацию :black_eye.:. Добавляем в эти запросы условие по id и в переменные пишется скалярное значение. Как бы сути вопроса это не меняет.
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 02:15
Цитата Сообщение от _katon_ Посмотреть сообщение
Добавляем в эти запросы условие по id и в переменные пишется скалярное значение. Как бы сути вопроса это не меняет.
Это как? умышленно игнорируем "лишние" изменения таблицы? может проще сразу от триггера отказаться, мороки меньше?
Или, если уж очень хочется скалярных переменных, курсор в триггере организовать?

Добавлено через 3 минуты
Хотя где-то в примерах мне попадалась конструкция типа
SQL
1
2
3
IF @@rowcount=1 BEGIN
   UPDATE anothertable SET ...
END
А смысл тогда какой в таком "частично работающем" триггере?
0
 Аватар для _katon_
414 / 265 / 25
Регистрация: 03.10.2011
Сообщений: 1,094
20.03.2013, 02:25
Вы не поняли? ключевой момент интересующий меня - высказывание iap по поводу того, что скалярная переменная в триггере по его убеждению - гавнокод. Так, что меня вообще не волнует правильно ли работает триггер и какие там синтаксические или логические ошибки (да простит меня ТС). Меня интересует только почему скалярная переменная в триггере зло????? А от всего остального я абстрагируюсь.
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 02:30
Встречный вопрос)) - а для чего в триггере использовать скаляры? Какие задачи без них нерешаемы (в триггере)?
0
1 / 1 / 0
Регистрация: 18.03.2013
Сообщений: 45
20.03.2013, 05:57  [ТС]
[QUOTE=cygapb-007;4280145]примерно так:
T-SQL
1
2
3
create table Группы(НомерГруппы int, КолвоСтудентов int)
create table Студенты(id int identity primary key, Фио varchar(50), НомерГруппы int)
go
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
create trigger Студенты_изменения on Студенты
after insert, update, delete as
-- Удаление студентов или перевод из группы
update g set g.КолвоСтудентов-=q.qty
   from Группы g
   join (select НомерГруппы, COUNT(*) qty from deleted group by НомерГруппы) q on q.НомерГруппы=g.НомерГруппы;
-- Добавление студентов или перевод в группу
merge Группы g 
   using (select НомерГруппы,count(*)qty from inserted group by НомерГруппы)q
   on  q.НомерГруппы=g.НомерГруппы
   when matched then update set g.КолвоСтудентов+=q.qty
   when not matched then insert (НомерГруппы, КолвоСтудентов) values (q.НомерГруппы, q.qty);
go
код компактнее конечно...
Я так понял этот триггер срабатывает сразу после 3 видов обновления?
И еще один тупой вопрос!

join (select НомерГруппы, COUNT(*) qty from deleted group by НомерГруппы) q on q.НомерГруппы=g.НомерГруппы;

Зачем например тут используется group by ? До сих пор не могу понять когда и зачем ее использовать....
0
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 09:01
Цитата Сообщение от Traffi Посмотреть сообщение
Зачем например тут используется group by ? До сих пор не могу понять когда и зачем ее использовать....
Если изменения по нескольким студентам - таблица Группы будет изменена один раз для каждого из измененных номеров групп, без группировки - будет (число повторов) изменений
0
1116 / 761 / 183
Регистрация: 27.11.2009
Сообщений: 2,272
20.03.2013, 09:28
Цитата Сообщение от _katon_ Посмотреть сообщение
Предположительно строковым переменным @insgroup, @updgroup задается значение поля "НомерГруппы" из табличек inserted и deleted соответственно. И в чем некашерность? То, что в данном случае это лишено смысла не означает, что в других случаях это неприменимо или вредно (никто же не может похвастаться, что видел все возможные кодирования всех возможных триггеров). Я для себя хочу установить почему это гавнокод, т.е. из каких соображений.
Я должен объяснить свою позицию.
Триггер срабатывает не на вставляемую, удаляемую, изменяемую запись,
а на само действие - один раз на весь INSERT, один раз на весь DELETE, один раз на весь UPDATE.
Все эти команды могут затрагивать сразу несколько записей, а не одну.
Отсюда следует, что псевдотаблицы deleted и inserted могут содержать много записей.
Присваивание скалярной переменной результата запроса из этих псевдотаблиц лишены смысла в этом случае.
Ибо в переменной может быть одно значение, а реально имеем много (миллионы!!!).
Всегда, гворите, обрабатывается одна строка? И что же это гарантирует?
Ну хоть напишите проверку количества обрабатываемых записей в начале триггера!
Это будет хотя бы по-программистски.
Правильным является использование в SQL-инструкциях триггера
непосредственно deleted и inserted без всяких переменных.
Причём в предположении, что они содержат ЛЮБОЕ количество записей.

Traffi, а что касается предложенного Вами триггера INSTEAD OF UPDATE, я вспомнил, что хотел спросить Вас,
как же Вы любой UPDATE таблицы [Студенты] заменяете UPDATEом поля ДРУГОЙ таблицы [Группы]?! Где сам UPDATE студентов-то?
2
1313 / 945 / 144
Регистрация: 17.01.2013
Сообщений: 2,348
20.03.2013, 10:02
Хочу прокомментировать еще один момент в предложенном варианте триггера. В нем предполагается, что если группы нет в таблице - ее можно "молча" создать, что в реальном случае, скорее всего, будет неверно. При отсутствии номера группы в таблице, скорее всего, должна сгенерироваться ошибка и выполниться ROLLBACK TRANSACTION
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
20.03.2013, 10:02
Помогаю со студенческими работами здесь

Триггер, вызывающий процедуру, в которой выполняется select к этой таблице (откуда был вызван триггер)
есть тригерр create or replace trigger quickstart.quickstart.ACRIONS_COMMIT_TR after update on quickstart.actions for each...

Т-Триггер на ИЛИ-НЕ элементах и что это за триггер?
Здравствуйте. Нужно построить схему Т-Триггера через ИЛИ-НЕ элементы. Вот сам триггер ...

Взаимодействие коллайдеров (триггер и не триггер)
подскажите почему не срабатывает коллайдер с тригером на коллайдере без тригера? и как выйти из этой ситуации private void...

Триггер
Здравствуйте. Помогите Помоги переделать код под триггер. Или сделать рабочим этот код WITH CTE AS ( SELECT...

Триггер
Доброго времени суток всем. Сразу опишу задачу. Имеются таблицы: 1.) Заказ (id int, статус int); 2.) Товары_заказа (id int,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
Установка Emscripten SDK (emsdk) и CMake на Windows для сборки C и C++ приложений в WebAssembly (Wasm)
8Observer8 30.01.2026
Чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. Система контроля версиями Git. . .
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru