Подтвердить что ты не робот

MySQL Trigger - сохранение SELECT в переменной

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

4b9b3361

Ответ 1

Вы можете объявлять локальные переменные в триггерах 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//

Ответ 2

`CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
  FOR EACH ROW
BEGIN
    **SET @tableId= (SELECT id FROM dummy LIMIT 1);**

END;`;

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

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

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

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