триггер перед обновлением, зная, какое поле изменилось [дубликат]

Чтобы сделать как ответ выше, вы можете переопределить метод фрагмента onAttach:

public static class DummySectionFragment extends Fragment{
...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        DBHelper = new DatabaseHelper(activity);
    }
}
57
задан jens 9 June 2011 в 18:43
поделиться

7 ответов

В качестве обходного пути вы можете использовать временную метку (старую и новую) для проверки, но это not обновляется, если в строке нет изменений. (Возможно, это источник путаницы? Потому что этот тоже называется «при обновлении», но не выполняется, когда не происходит никаких изменений). Изменения в течение одной секунды не будут выполнять ту часть триггера, но в некоторых случаях это может быть хорошо (например, когда у вас есть приложение, которое все равно отклоняет быстрые изменения.)

Например, вместо

IF NEW.a <> OLD.a or NEW.b <> OLD.b /* etc, all the way to NEW.z <> OLD.z */ 
THEN  
  INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF

вы можете использовать

IF NEW.ts <> OLD.ts 
THEN  
  INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF

Then

РЕДАКТИРОВАТЬ: Добавлен полный пример

create table foo (a INT, b INT, ts TIMESTAMP);
create table bar (a INT, b INT);

INSERT INTO foo (a,b) VALUES(1,1);
INSERT INTO foo (a,b) VALUES(2,2);
INSERT INTO foo (a,b) VALUES(3,3);

DELIMITER ///

CREATE TRIGGER ins_sum AFTER UPDATE ON foo
    FOR EACH ROW
    BEGIN
        IF NEW.ts <> OLD.ts THEN  
            INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b);
        END IF;
    END;
///

DELIMITER ;

select * from foo;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    1 |    1 | 2011-06-14 09:29:46 |
|    2 |    2 | 2011-06-14 09:29:46 |
|    3 |    3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
3 rows in set (0.00 sec)

-- UPDATE without change
UPDATE foo SET b = 3 WHERE a = 3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

-- the timestamo didnt change
select * from foo WHERE a = 3;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    3 |    3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
1 rows in set (0.00 sec)

-- the trigger didn't run
select * from bar;
Empty set (0.00 sec)

-- UPDATE with change
UPDATE foo SET b = 4 WHERE a=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

-- the timestamp changed
select * from foo;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    1 |    1 | 2011-06-14 09:29:46 |
|    2 |    2 | 2011-06-14 09:29:46 |
|    3 |    4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
3 rows in set (0.00 sec)

-- and the trigger ran
select * from bar;
+------+------+---------------------+
| a    | b    | ts                  |
+------+------+---------------------+
|    3 |    4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
1 row in set (0.00 sec)

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

Документация находится здесь: https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization. html

desc foo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| a     | int(11)   | YES  |     | NULL              |                             |
| b     | int(11)   | YES  |     | NULL              |                             |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
63
ответ дан Pang 19 August 2018 в 05:43
поделиться
  • 1
    Я не вижу, как это может сработать. Не могли бы вы более подробно объяснить, что вы подразумеваете под этим. – jens 10 June 2011 в 07:42
  • 2
    @derkommissar: Я добавил пример – Inca 10 June 2011 в 18:34
  • 3
    спасибо. ваше предложение работает. Я добавил полный пример. – jens 14 June 2011 в 09:15
  • 4
    Есть ли доступная ссылочная ссылка – Pavan Jaju 18 February 2016 в 18:46
  • 5
    Это не будет работать, если частота обновления меньше секунды. Временная метка изменится (но до того же значения). Вы должны использовать временную метку (6), которая должна быть достаточно точной, отслеживая все обновления – Sir Rufo 20 June 2016 в 10:42

Используйте следующий запрос, чтобы увидеть, какие строки имеют изменения:

(select * from inserted) except (select * from deleted)

Результаты этого запроса должны состоять из всех новых записей, отличных от старых.

1
ответ дан Enamul Hassan 19 August 2018 в 05:43
поделиться
  • 1
    К сожалению, это не отвечает на вопрос. Обновления не удаляют строки, а ОП пытается остановить запуск триггера, если обновление не изменило никаких данных (обновление столбца со значением 1 до значения 1 не изменяет никаких данных, но операция обновления все еще выполняется, поэтому триггер тоже). – Takarii 3 August 2016 в 13:58
  • 2
    Насколько я понимаю, запрос UPDATE будет помещать значения OLD в удаленный набор записей и НОВЫЕ значения во вставленный набор записей. Хотя это не будет препятствовать запуску триггера, его можно использовать, чтобы предотвратить срабатывание триггера, что обычно является достаточным. – Hawthorne 3 August 2016 в 14:02
  • 3
    возможно, стоит проиллюстрировать ваш ответ расширенным кодом. Однако имейте в виду, что этому вопросу также 5 лет. – Takarii 3 August 2016 в 14:09
  • 4
    Вот цитата из Microsoft Операция обновления похожа на операцию удаления, за которой следует операция вставки; старые строки сначала копируются в удаленную таблицу, а затем новые строки копируются в таблицу триггеров и в вставленную таблицу. & quot; – Hawthorne 3 August 2016 в 14:11
  • 5
    Пример кода: CREATE TRIGGER ins_sum ПОСЛЕ ОБНОВЛЕНИЯ ON foo INSERT INBAR VALUES (выберите * из вставленного, кроме select * из удаленных); – Hawthorne 3 August 2016 в 14:28
MYSQL TRIGGER BEFORE UPDATE IF OLD.a<>NEW.b

USE `pdvsa_ent_aycg`;

DELIMITER $$

CREATE TRIGGER `cisterna_BUPD` BEFORE UPDATE ON `cisterna` FOR EACH ROW

BEGIN

IF OLD.id_cisterna_estado<>NEW.id_cisterna_estado OR OLD.observacion_cisterna_estado<>NEW.observacion_cisterna_estado OR OLD.fecha_cisterna_estado<>NEW.fecha_cisterna_estado

    THEN 

        INSERT INTO cisterna_estado_modificaciones(nro_cisterna_estado, id_cisterna_estado, observacion_cisterna_estado, fecha_cisterna_estado) values (NULL, OLD.id_cisterna_estado, OLD.observacion_cisterna_estado, OLD.fecha_cisterna_estado); 

    END IF;

END
0
ответ дан fantaghirocco 19 August 2018 в 05:43
поделиться

НО представьте себе большую таблицу с изменяющимися столбцами. Вы должны сравнить каждый столбец, и если в базе данных изменится настройка триггера. И не «хорошо» сравнивать каждую строку с жестким кодом:)

Да, но это способ продолжения.

В качестве побочного примечания, это также Перед тем, как обновить, проверьте правильную практику:

UPDATE foo SET b = 3 WHERE a=3 and b <> 3;

В вашем примере это позволит обновить (и, таким образом, переписать) две строки вместо трех.

15
ответ дан Johan 19 August 2018 в 05:43
поделиться
  • 1
    @Denis, это not необходимо, MySQL проверяет, действительно ли значение изменилось и только запускает UPDATE (update + trigger), если есть необходимость. Ваш чек просто замедляет работу. – Johan 9 June 2011 в 17:56
  • 2
    @Johan: Это необходимо, и MySQL этого не делает. Он бы не уважал стандарт SQL, если бы это было так, и OP не задавал бы его вопроса в первую очередь. – Denis de Bernardy 9 June 2011 в 17:59
  • 3
  • 4
    @Yohan: вы можете найти это обсуждение интересным. – Denis de Bernardy 9 June 2011 в 18:16
  • 5
    @Denis, хорошая ссылка. pgS - действительно хороший db :-). – Johan 9 June 2011 в 18:19

Здесь, если какая-либо строка влияет на новую вставку, тогда она будет обновляться в другой таблице в базе данных.

DELIMITER $$

CREATE TRIGGER "give trigger name" AFTER INSERT ON "table name" 
FOR EACH ROW
BEGIN
    INSERT INTO "give table name you want to add the new insertion on previously given table" (id,name,age) VALUES (10,"sumith",24);
END;
$$
DELIMITER ;
2
ответ дан sumith madhushan 19 August 2018 в 05:43
поделиться

Вы можете сделать это, сравнивая каждое поле, используя оператор NULL-safe equals <=> , а затем , отрицая результат, используя NOT .

Полный триггер станет следующим:

DROP TRIGGER IF EXISTS `my_trigger_name`;

DELIMITER $$

CREATE TRIGGER `my_trigger_name` AFTER UPDATE ON `my_table_name` FOR EACH ROW 
    BEGIN
        /*Add any fields you want to compare here*/
        IF !(OLD.a <=> NEW.a AND OLD.b <=> NEW.b) THEN
            INSERT INTO `my_other_table` (
                `a`,
                 `b`
            ) VALUES (
                NEW.`a`,
                NEW.`b`
            );
        END IF;
    END;$$

DELIMITER ;

(На основании другого ответа моего .)

8
ответ дан user2428118 19 August 2018 в 05:43
поделиться

Я не могу ответить, поэтому просто будьте осторожны, если в столбце поддерживаются значения NULL, OLD.x & lt;> NEW.x не достаточно, потому что

SELECT IF(1<>NULL,1,0)

возвращает 0 как и

NULL<>NULL 1<>NULL 0<>NULL 'AAA'<>NULL

Таким образом, он не будет отслеживать изменения FROM и TO NULL

Правильный способ в этом сценарии -

((OLD.x IS NULL AND NEW.x IS NOT NULL) OR (OLD.x IS NOT NULL AND NEW.x IS NULL) OR (OLD.x<>NEW.x))
12
ответ дан Wax Cage 19 August 2018 в 05:43
поделиться
  • 1
    Спасибо за ваш ценный ответ / подсказку! Это делает решение timestamp еще более привлекательным, а сравнительное решение практически непригодно. – jens 30 January 2014 в 00:24
  • 2
    Или вы можете использовать COALESCE(), который возвращает первый из своих аргументов, который не является NULL. Таким образом, вы можете записать его как IF COALESCE(OLD.X,'') <> COALESCE(NEW.X,'') – Lyman Zerga 5 February 2014 в 02:20
  • 3
    Или просто используйте оператор сравнения mysql с нулевым значением <=>. – djmj 27 March 2014 в 02:27
Другие вопросы по тегам:

Похожие вопросы: