0

In my database there are four tables: task, tasknotes, task_archive and tasknotes_archive. When an entry is copied from the task table to the task_archive table I want to use a trigger to perform the following:

  1. copy the related task notes from the tasknotes table to the tasknotes_archive table.
  2. delete the entry in the task table I just copied to task_archive
  3. delete the entries from tasknotes that I just copied to tasknotes_archive

The application that interfaces with the database is built in Java using JDBC. I could achieve the above results as either a series of calls to the database or as a transaction. However it would seem more efficient to have the initial insert statement than copies the row from task to task_archive trigger the rest of the events. I initially tested this by seeing if I could get a trigger to delete the entry from the task table based on the insert into task_archive. This seemed to work fine. However when I started trying to add in the script to cause the DB to copy from tasknotes to tasknotes_archive I got error messages stating that it doesn't recognise task_archive.task_id in the first where clause. Importantly, tasknotes and tasknotes_archive have the exact same table structure so this insert method should be possible as discussed in the answer to this question: MYSQL: How to copy an entire row from one table to another in mysql with the second table having one extra column?. I then tried changing this to new.task_id based on answers to other questions on stack. Still got error messages. The following code is the insert trigger contained in task_archive, which should I'm trying to develop to perform the above actions on tasknotes_archive and task:

CREATE
TRIGGER `myDB`.`task_archive_AFTER_INSERT`
AFTER INSERT ON `myDB`.`task_archive`
FOR EACH ROW
BEGIN
INSERT INTO tasknotes_archive
SELECT tasknotes.* FROM tasknotes
WHERE tasknotes.task_id = task_archive.task_id;

DELETE FROM task
USING task, task_archive
WHERE task.task_id = task_archive.task_id;
END

My question is, is it possible to have multiple events run as a trigger as described? Am I correct in assuming this is a more efficient way of performing this rather than multiple calls to the DB in java? Finally, what is the correct way to write this trigger?

Jay Black
  • 107
  • 2
  • 12
  • You're copying ALL rows from `tasknotes` to `tasknotes_archive`, not just the ones related to the current task. – Barmar Jan 21 '19 at 10:13
  • Your `DELETE` syntax is just plain wrong. You need to use `JOIN`, not `USING`. `DELETE task, tasknotes FROM task JOIN tasknotes ON ... WHERE ...` – Barmar Jan 21 '19 at 10:15
  • Both queries need a `WHERE` clause that uses `NEW.task_id`. to find rows related to the current row being archived. – Barmar Jan 21 '19 at 10:16
  • @Barmar the DELETE statement works fine on its own when the INSERT statement prior to it is removed. If it works why is it wrong or rather, why is it the wrong way to do it? – Jay Black Jan 21 '19 at 10:22
  • Ah, I see that `USING` is an alternate syntax in `DELETE`. – Barmar Jan 21 '19 at 10:26

1 Answers1

1

You need to use NEW.task_id to get the task related to the current row of the trigger.

And if you're doing this using a CLI, you need the DELIMITER statement so you can have ; between the statements in the trigger.

DELIMITER $$

CREATE
TRIGGER `myDB`.`task_archive_AFTER_INSERT`
AFTER INSERT ON `myDB`.`task_archive`
FOR EACH ROW
BEGIN
    INSERT INTO tasknotes_archive
    SELECT tasknotes.* FROM tasknotes
    WHERE tasknotes.task_id = NEW.task_id;

    DELETE task, tasknotes
    FROM task JOIN tasknotes USING (task_id)
    WHERE task.task_id = NEW.task_id;
END
$$
DELIMITER ;
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks for the above. I can follow the logic but I'm still getting errors. To be clear, the trigger code is attached to inserts on my task_archive table and should fire when a new task is copied into it. I think the above assumes the trigger is on the tasknotes_archive table? the insert code fails with an error message Incorrect integer value: 'john smith' for column 'task_id' at row 19. what I'm trying to achieve is 'Get the tasknotes associated with the task_id of the entry just instered in task_archive and copy the entries in tasknotes with the same task_id into tasknotes_archive.' – Jay Black Jan 21 '19 at 11:05
  • It sounds like the columns are in different order in the two tables. If you use `INSERT INTO table1 SELECT * FROM table2` they have to match up exactly. If they don't, you need to use `INSERT INTO table1 (col1, col2, col3, ...) SELECT col1, col2, col3, ... FROM table2` – Barmar Jan 21 '19 at 16:21
  • Or change the archive tables so their columns are in the same order as the original tables. – Barmar Jan 21 '19 at 16:22
  • I did have a mistake in the `DELETE` query, I had `JOIN task_archive` when it should be `JOIN tasknotes`. – Barmar Jan 21 '19 at 16:23
  • Thanks. After much playing about with your solution, I couldn't get a version that worked. I ended up going for a compromise. I wrote the code to copy the data from 'task' to 'task_archive' and 'tasknote' to 'tasknote_archive' as a transaction statement in java. I then wrote triggers in the both archive tables to delete from the non-archive tables on insert. This works. Though I imagine it could be more efficient. The tables match. Thanks for your help, it helped me arrive at a working solution :) – Jay Black Jan 21 '19 at 16:29
  • 1
    That was the only reason I could think of why it said that `john smith` was an incorrect value for `task_id`, because the `tasknotes` table has the username where the task ID column should be. – Barmar Jan 21 '19 at 16:33
  • It stumped me. I couldn't solve it as they're both exactly the same in structure and datatype. The java solution works though. I might revisit this when I get this iteration finished as I don't like not knowing why somethings not doing what it should. If I managed to solve it when I do, I'll add an update to my question – Jay Black Jan 21 '19 at 16:36