Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Процедуры, функции, тригеры
 
 автор: Sfinks   (23.09.2012 в 19:42)   письмо автору
 
 

Есть у кого-нибудь хорошая, а главное понятная статья по теме?
Желательно с примерами.
Ничего понятного не могу найти!

  Ответить  
 
 автор: cheops   (24.09.2012 в 21:18)   письмо автору
 
   для: Sfinks   (23.09.2012 в 19:42)
 

Именно по MySQL? Мы освещали это в нашей книге "MySQL. На примерах".

  Ответить  
 
 автор: Sfinks   (25.09.2012 в 18:45)   письмо автору
 
   для: cheops   (24.09.2012 в 21:18)
 

Да, именно по MySQL.
_____________
Книга - это конечно хорошо, но, как всегда - долго =)
Мне кажется для начала понимания хватило бы стартового "пинка" =)
Вот можете, например, показать как сделать триггер, чтоб перед удалением записи из таблицы, проверялась связанная с ней таблица на использование внешнего ключа? И если в связанной таблице используется удаляемый ключ, сперва удалялись эти записи из связанной таблицы, а потом уже из основной.

  Ответить  
 
 автор: cheops   (26.09.2012 в 10:47)   письмо автору
 
   для: 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, которую вам не видать как своих ушей.

  Ответить  
 
 автор: Sfinks   (26.09.2012 в 14:09)   письмо автору
 
   для: 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-Да

  Ответить  
 
 автор: cheops   (26.09.2012 в 14:50)   письмо автору
 
   для: Sfinks   (26.09.2012 в 14:09)
 

Ему не нравится разделитель ;, которым пестрит тело триггера, в PMA внизу есть поле "Разделитель", поместите туда что угодно, кроме ; для выполнения триггера. Тогда тело триггер будет восприниматься как единый оператор. Если помимо триггера нужно выполнить еще какие-то запросы, то они должны заканчиваться разделителем, который вы указали в поле "Разделитель".

  Ответить  
 
 автор: Sfinks   (26.09.2012 в 16:15)   письмо автору
 
   для: cheops   (26.09.2012 в 14:50)
 

Тьфу ты ё моё =))) Вот в чем дело! =)))))) Ну тады понятно! Спасибо!

[UPD] А как теперь можно посмотреть что на базу навешано, какие процедуры и т.п.?
И если нужно изменить, есть какой-то ALTER/UPDATE для тригеров или просто CREATE одноименный?

  Ответить  
 
 автор: cheops   (26.09.2012 в 17:39)   письмо автору
 
   для: Sfinks   (26.09.2012 в 16:15)
 

Можно через информационную схему, можно через SHOW TRIGGERS, удалить можно через DROP TRIGGER, редактирование не предусмотрено (если только в новые версии не добавили).

  Ответить  
 
 автор: Sfinks   (26.09.2012 в 19:46)   письмо автору
 
   для: cheops   (26.09.2012 в 17:39)
 

Ага, понятно!
Ну теперь и со всеми остальными статьями будет яснее!
Спасибо =)

  Ответить  
 
 автор: Sfinks   (28.09.2012 в 10:04)   письмо автору
 
   для: Sfinks   (26.09.2012 в 19:46)
 

А триггеры вызывают цепную реакцию?
В смысле при срабатывании триггера AFTER INSERT одной таблицы происходит UPDATE другой, на которой, в свою очередь, стоит BEFORE UPDATE.
Он тоже сработает?

  Ответить  
 
 автор: cheops   (28.09.2012 в 11:07)   письмо автору
 
   для: Sfinks   (28.09.2012 в 10:04)
 

Да, должен.

  Ответить  
 
 автор: Sfinks   (28.09.2012 в 11:16)   письмо автору
 
   для: 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 в 23:04)   письмо автору
 
   для: Sfinks   (28.09.2012 в 11:16)
 

Выкрутился, совместив и "INSERT ... ON DUPLICATE KEY UPDATE" и "CREATE TRIGGER ... BEFORE INSERT"!
/*<?*/
CREATE TRIGGER `productBeforeInsertBEFORE 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 `productBeforeInsertBEFORE 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

  Ответить  
 
 автор: cheops   (29.09.2012 в 07:40)   письмо автору
 
   для: Sfinks   (28.09.2012 в 11:16)
 

Об триггерах следует знать вот еще какую вещь, помимо NEW.parameter1 у вас есть старое значение OLD.parameter1, поэтому вы всегда можете подставить старые значения.

  Ответить  
 
 автор: Sfinks   (29.09.2012 в 08:44)   письмо автору
 
   для: cheops   (29.09.2012 в 07:40)
 

Это при апдейте. А тут была проблема в том, что апдейт не срабатывал.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования