MySQL триггер для обновления поля до значения id - PullRequest
17 голосов
/ 31 июля 2009

Я хотел бы иметь триггер для выполнения следующей операции для вставленных записей:

 # pseudocode
 if new.group_id is null
    set new.group_id = new.id
 else
    # don't touch it
 end

Более четко: скажем, у меня одна таблица с тремя столбцами: id первичный ключ, group_id int, value varchar.

Когда я вставляю с group_id вот так:

INSERT INTO table(value, group_id) VALUES ('a', 10)

Я бы хотел иметь:

id | group_id | value
---+----------+------
 1 |       10 | a

но когда я опускаю group_id:

INSERT INTO table(value) VALUES ('b')

это должно быть автоматически установлено на id этой записи:

id | group_id | value
---+----------+------
 2 |        2 | b

Возможно ли это с помощью триггера? (Я знаю, что могу обновить запись после вставки, но наличие триггера было бы лучше.)

Ответы [ 6 ]

28 голосов
/ 28 сентября 2009

Я не знаю ни одного способа сделать это одним оператором, даже используя триггер.

Триггерное решение, предложенное @Lucky, будет выглядеть в MySQL следующим образом:

CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
  SET NEW.group_id = COALESCE(NEW.group_id, NEW.id);
END

Однако есть проблема. На этапе BEFORE INSERT автоматически сгенерированное значение id еще не было сгенерировано. Поэтому, если group_id равно нулю, по умолчанию используется NEW.id, что всегда равно 0.

Но если вы измените этот триггер на срабатывание во время фазы AFTER INSERT, чтобы у вас был доступ к сгенерированному значению NEW.id, вы не сможете изменить значения столбца.

MySQL не поддерживает выражения для DEFAULT столбца, поэтому вы не можете также объявить это поведение в определении таблицы.

Единственное решение - сделать INSERT, а затем сразу же сделать UPDATE, чтобы изменить group_id, если он не установлен.

INSERT INTO MyTable (group_id, value) VALUES (NULL, 'a');
UPDATE MyTable SET group_id = COALESCE(group_id, id) WHERE id = LAST_INSERT_ID();
1 голос
/ 18 декабря 2018

Это работает для меня

DELIMITER $$
CREATE TRIGGER `myTriggerNameHere`
BEFORE INSERT ON `table` FOR EACH ROW
BEGIN
    SET NEW.group_id = IF(NEW.group_id IS NULL, LAST_INSERT_ID()+1, NEW.group_id);
END;
$$
DELIMITER ;
1 голос
/ 14 июня 2017

Я отвечаю здесь, как и в принятом ответе Билл Карвин заявляет:

На этапе BEFORE INSERT автоматически сгенерированное значение id не было генерируется еще. Так что если group_id равен нулю, по умолчанию используется NEW.id, который всегда 0.


У меня есть ответ на этот вопрос - для OP (и для посетителей), вот несколько моментов: Вы не можете обновить таблицу, из которой вызывается триггер, для нее вы получите Ошибка 1442 :

Error Code: 1442
Can't update table 'MyTable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

1. Обновление новой строки Используйте триггер BEFORE INSERT ON, таким образом вы можете обновить все поля для новой строки, которые могут быть доступны через оператор NEW, т.е.

set NEW.group_id = NEW.id

2. Получить значение auto_increment перед вставкой :

SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='MyTable'

Подводя итог - триггер SQL для будет выглядеть следующим образом:

DELIMITER //
DROP TRIGGER IF EXISTS MyTrigger//
CREATE TRIGGER MyTrigger BEFORE INSERT ON MyTable
FOR EACH ROW BEGIN
    IF new.group_id IS NULL
        set @auto_id := (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES
                         WHERE TABLE_NAME='MyTable' AND TABLE_SCHEMA=DATABASE() ); 
        set NEW.group_id = @auto_id;
    ENF IF;
END;
//
DELIMITER ;
0 голосов
/ 15 января 2013

В этой ситуации триггер выглядит избыточным Просто примените значение по умолчанию.

CREATE TABLE `test` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `value` varchar(100) NOT NULL,
    `group_id` TINYINT(3) UNSIGNED NOT NULL DEFAULT '2'
)
0 голосов
/ 11 августа 2009

Этот триггер должен делать то, что вы просили.

   CREATE TRIGGER mytrigger BEFORE INSERT ON mytable
          IF new.group_id IS NULL
            SET new.group_id = new.id
          END IF
      END;

Он скопирован с очень похожего примера на странице MYSQL .

0 голосов
/ 31 июля 2009

Я считаю, что это будет работать для вас

У меня есть две таблицы

test_b: a_id, value
test_c: a_id, value

А вот триггер на вставке теста б. Он проверяет, имеет ли значение a_id значение null, и вставляет ли он 0

CREATE TRIGGER test_b AFTER INSERT ON test_b
  FOR EACH ROW 
    INSERT INTO test_c (a_id, value) VALUES (IFNULL(NEW.a_id, 0),NEW.value)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...