|
|
|
| Есть у кого-нибудь хорошая, а главное понятная статья по теме?
Желательно с примерами.
Ничего понятного не могу найти! | |
|
|
|
|
|
|
|
для: Sfinks
(23.09.2012 в 19:42)
| | Именно по MySQL? Мы освещали это в нашей книге "MySQL. На примерах". | |
|
|
|
|
|
|
|
для: cheops
(24.09.2012 в 21:18)
| | Да, именно по MySQL.
_____________
Книга - это конечно хорошо, но, как всегда - долго =)
Мне кажется для начала понимания хватило бы стартового "пинка" =)
Вот можете, например, показать как сделать триггер, чтоб перед удалением записи из таблицы, проверялась связанная с ней таблица на использование внешнего ключа? И если в связанной таблице используется удаляемый ключ, сперва удалялись эти записи из связанной таблицы, а потом уже из основной. | |
|
|
|
|
|
|
|
для: Sfinks
(25.09.2012 в 18:45)
| | Давайте попробуем вас "пнуть" :)))
Сразу нужно сказать, что настоящие внешние ключи из InnoDB с триггерами не работают (впрочем им это и не нужно - они сами себе триггеры). Пусть имеется незамысловатая база данных из двух MyISAM-таблиц, каталогов и позиций, связанных через поле id_catalog
CREATE TABLE catalog (
id_catalog int(11) NOT NULL,
`name` tinytext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
INSERT INTO catalog VALUES(1, 'PHP');
INSERT INTO catalog VALUES(2, 'MySQL');
CREATE TABLE position (
id_position int(11) NOT NULL,
`name` tinytext NOT NULL,
id_catalog int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
INSERT INTO position VALUES(1, 'Строки', 1);
INSERT INTO position VALUES(2, 'Массивы', 1);
INSERT INTO position VALUES(3, 'Объекты', 1);
INSERT INTO position VALUES(4, 'SELECT', 2);
INSERT INTO position VALUES(5, 'DELETE', 2);
|
Создадим триггер deletecatalog для события DELETE таблицы catalog
CREATE TRIGGER deletecatalog BEFORE DELETE
ON catalog FOR EACH ROW
BEGIN
SET @id_catalog = OLD.id_catalog;
DELETE FROM position WHERE id_catalog = @id_catalog;
END
| теперь удаление из таблицы catalog, будет приводить к удалению из таблицы position
DELETE FROM catalog WHERE id_catalog = 2;
|
PS Только не сильно радуйтесь, все это великолепие доступно, если вы используете СУБД MySQL после версии 5.1.6 и администратор вам дал привилегию TRIGGER, если версия ниже, то нужна привилегия SUPER, которую вам не видать как своих ушей. | |
|
|
|
|
|
|
|
для: cheops
(26.09.2012 в 10:47)
| | Во-во.... И где это "CREATE TRIGGER" писать?
На локалхосте в ПМА выбрал БД test, на вкладке SQL выполнил первый набор запросов (create/insert), затем там же скопипастил и выполнил CREATE TRIGGER ....
Ответ: #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 4
Версия MySQL - 5.5.27, пользователь root, Глобальные привилегии - ALL PRIVILEGES, GRANT-Да | |
|
|
|
|
|
|
|
для: Sfinks
(26.09.2012 в 14:09)
| | Ему не нравится разделитель ;, которым пестрит тело триггера, в PMA внизу есть поле "Разделитель", поместите туда что угодно, кроме ; для выполнения триггера. Тогда тело триггер будет восприниматься как единый оператор. Если помимо триггера нужно выполнить еще какие-то запросы, то они должны заканчиваться разделителем, который вы указали в поле "Разделитель". | |
|
|
|
|
|
|
|
для: cheops
(26.09.2012 в 14:50)
| | Тьфу ты ё моё =))) Вот в чем дело! =)))))) Ну тады понятно! Спасибо!
[UPD] А как теперь можно посмотреть что на базу навешано, какие процедуры и т.п.?
И если нужно изменить, есть какой-то ALTER/UPDATE для тригеров или просто CREATE одноименный? | |
|
|
|
|
|
|
|
для: Sfinks
(26.09.2012 в 16:15)
| | Можно через информационную схему, можно через SHOW TRIGGERS, удалить можно через DROP TRIGGER, редактирование не предусмотрено (если только в новые версии не добавили). | |
|
|
|
|
|
|
|
для: cheops
(26.09.2012 в 17:39)
| | Ага, понятно!
Ну теперь и со всеми остальными статьями будет яснее!
Спасибо =) | |
|
|
|
|
|
|
|
для: Sfinks
(26.09.2012 в 19:46)
| | А триггеры вызывают цепную реакцию?
В смысле при срабатывании триггера AFTER INSERT одной таблицы происходит UPDATE другой, на которой, в свою очередь, стоит BEFORE UPDATE.
Он тоже сработает? | |
|
|
|
|
|
|
|
для: Sfinks
(28.09.2012 в 10:04)
| | Да, должен. | |
|
|
|
|
|
|
|
для: cheops
(28.09.2012 в 11:07)
| | И еще вопрос.
Можно отменить действие по умолчанию вызвавшее триггер? Как в JS: return false;
Например как написать такое:
CREATE TRIGGER insertPosition BEFORE INSERT
ON position FOR EACH ROW
BEGIN
SET @par1 = NEW.parameter1;
SET @par2 = NEW.parameter2;
Если есть запись с parameter1=@par1 и parameter2=@par2, то{
установить значение ее поля status='active'
не добавлять новую запись
}
иначе{
Добавить запись
}
END
|
Другими словами аналог "INSERT ... ON DUPLICATE KEY UPDATE", но триггером.
Это возможно?
[UPD]
"INSERT ... ON DUPLICATE KEY UPDATE" -это конечно хорошо, но не срабатывает, когда UNIQUE KEY составной и одно из добавляемых полей IS NULL. Дубликаты вставляются.
Допустим отменить добавление новой записи можно задав одному из полей не допустимое значение, например NEW.field1=null для поля которое не может быть null.
Или есть человеческий (не извращенский) способ? | |
|
|
|
|
|
|
|
для: Sfinks
(28.09.2012 в 11:16)
| | Выкрутился, совместив и "INSERT ... ON DUPLICATE KEY UPDATE" и "CREATE TRIGGER ... BEFORE INSERT"!
/*<?*/
CREATE TRIGGER `productBeforeInsert` BEFORE INSERT ON `product`
FOR EACH ROW BEGIN
/* чтобы не делать лишних телодвижений выполняю всю обработку только если проблемное поле IS NULL */
IF NEW.product_color IS NULL THEN
/* Проверяю есть ли уже в интересующей выборке запись в которой проблемное поле IS NULL */
SELECT count(*) INTO @co FROM product WHERE price_id=NEW.price_id AND product_color IS NULL;
/* ...если есть... */
IF @co > 0 THEN
/* то определяю значение PRIMARY KEY этой записи */
SELECT product_id INTO @id FROM product WHERE price_id=NEW.price_id AND product_color IS NULL;
/* и присваиваю его значению PRIMARY KEY добавляемой записи */
SET NEW.product_id = @id;
/* вынуждая тем самым сработать ON DUPLICATE KEY UPDATE */
END IF;
END IF;
END
|
Получилось красиво =)))
[UPD] А еще красивее будет убрать лишнюю проверку, т.к. если подходящей строки нет, то @id IS NULL =)
/*<?*/
CREATE TRIGGER `productBeforeInsert` BEFORE INSERT ON `product`
FOR EACH ROW BEGIN
IF NEW.product_color IS NULL THEN
SELECT product_id INTO @id FROM product WHERE price_id=NEW.price_id AND product_color IS NULL;
SET NEW.product_id = coalesce(@id,NEW.product_id);
END IF;
END
|
| |
|
|
|
|
|
|
|
для: Sfinks
(28.09.2012 в 11:16)
| | Об триггерах следует знать вот еще какую вещь, помимо NEW.parameter1 у вас есть старое значение OLD.parameter1, поэтому вы всегда можете подставить старые значения. | |
|
|
|
|
|
|
|
для: cheops
(29.09.2012 в 07:40)
| | Это при апдейте. А тут была проблема в том, что апдейт не срабатывал. | |
|
|
|