MySQL Trigger - Сохранение SELECT в переменной - PullRequest
52 голосов
/ 27 ноября 2008

У меня есть триггер, в котором я хочу, чтобы переменная содержала INT, который я получаю из SELECT, поэтому я могу использовать его в двух операторах IF вместо двойного вызова SELECT. Как вы объявляете / используете переменные в триггерах MySQL?

Ответы [ 5 ]

49 голосов
/ 30 ноября 2008

Вы можете объявить локальные переменные в триггерах MySQL, используя синтаксис DECLARE.

Вот пример:

DROP TABLE IF EXISTS foo;
CREATE TABLE FOO (
  i SERIAL PRIMARY KEY
);

DELIMITER //
DROP TRIGGER IF EXISTS bar //

CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = NEW.i;
  SET @a = x; -- set user variable outside trigger
END//

DELIMITER ;

SET @a = 0;

SELECT @a; -- returns 0

INSERT INTO foo () VALUES ();

SELECT @a; -- returns 1, the value it got during the trigger

Когда вы присваиваете значение переменной, вы должны убедиться, что запрос возвращает только одно значение, а не набор строк или набор столбцов. Например, если ваш запрос на практике возвращает одно значение, это нормально, но как только он возвращает более одной строки, вы получите «ERROR 1242: Subquery returns more than 1 row».

Вы можете использовать LIMIT или MAX(), чтобы убедиться, что для локальной переменной задано одно значение.

CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = (SELECT age FROM users WHERE name = 'Bill'); 
  -- ERROR 1242 if more than one row with 'Bill'
END//

CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
  DECLARE x INT;
  SET x = (SELECT MAX(age) FROM users WHERE name = 'Bill');
  -- OK even when more than one row with 'Bill'
END//
7 голосов
/ 28 ноября 2008
`CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
  FOR EACH ROW
BEGIN
    **SET @tableId= (SELECT id FROM dummy LIMIT 1);**

END;`;
6 голосов
/ 15 мая 2009
CREATE TRIGGER clearcamcdr AFTER INSERT ON `asteriskcdrdb`.`cdr` 
FOR EACH ROW
BEGIN
  SET @INC = (SELECT sip_inc FROM trunks LIMIT 1);
  IF NEW.billsec >1 AND NEW.channel LIKE @INC 
    AND NEW.dstchannel NOT LIKE "" 
  THEN
    insert into `asteriskcdrdb`.`filtre` (id_appel,date_appel,source,destinataire,duree,sens,commentaire,suivi) 
      values (NEW.id,NEW.calldate,NEW.src,NEW.dstchannel,NEW.billsec,"entrant","",""); 
  END IF;
END$$

Не пытайтесь это @ home

2 голосов
/ 28 ноября 2008

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

1 голос
/ 20 декабря 2016

Я публикую это решение, потому что мне было трудно найти то, что мне нужно. Этот пост достаточно близко подошел мне (+1 за это спасибо), и вот окончательное решение для реорганизации данных столбца перед вставкой, если данные соответствуют тесту .

Примечание: это из устаревшего проекта Я унаследовал где:

  1. Уникальный ключ - это состав из rridprefix + rrid
  2. До того, как я вступил во владение, не было никаких ограничений, препятствующих дублированию уникальных ключей
  3. Нам нужно было объединить две таблицы (одна полная дубликатов) в основную таблицу, которая теперь имеет ограничение на составной ключ (поэтому объединение не удастся, потому что получающая таблица не будет разрешать дубликаты из нечистой таблицы)
  4. on duplicate key не идеально, поскольку столбцы слишком многочисленны и могут измениться

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

BEGIN
  -- prevent duplicate composite keys when merging in archive to main
  SET @EXIST_COMPOSITE_KEY = (SELECT count(*) FROM patientrecords where rridprefix = NEW.rridprefix and rrid = NEW.rrid);

  -- if the composite key to be introduced during merge exists, rearrange the data for insert
  IF @EXIST_COMPOSITE_KEY > 0
  THEN

    -- set the incoming column data this way (if composite key exists)

    -- the legacy duplicate rrid field will help us keep the bad data
    SET NEW.legacyduperrid = NEW.rrid;

    -- allow the following block to set the new rrid appropriately
    SET NEW.rrid = null;

  END IF;

  -- legacy code tried set the rrid (race condition), now the db does it
  SET NEW.rrid = (
    SELECT if(NEW.rrid is null and NEW.legacyduperrid is null, IFNULL(MAX(rrid), 0) + 1, NEW.rrid)
    FROM patientrecords
    WHERE rridprefix  = NEW.rridprefix
  );
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...