Triggering mysql delete in another table? - sql

I have 3 tables in my database:
| systems |
|-------------|
| system_id |
|-------------|
| systems_maintenances |
|-------------------------|
| systems_maintenances_id|
| system_id |
| maintenance_id |
|-------------------------|
| maintenances |
|-------------------------|
| maintenance_id |
|-------------------------|
I'd like that when I delete a system, the maintenance being deleted too.
For the moment it only deletes in the systems_maintenances table.
I think a trigger is the best (and only?) way to do that.
I created this one:
CREATE TRIGGER `deleteMaintenance` BEFORE DELETE ON `systems`
FOR EACH ROW BEGIN
DELETE FROM maintenances
WHERE maintenance_id = systems_maintenances.maintenance_id;
END
The problem is I get the error:
DELETE FROM SNMProject.systems WHERE systems.system_id =16
MySQL a répondu:
#1054 - Unknown column 'systems_maintenances.maintenance_id' in 'where clause
How to solve my problem?
I don't know if it can help but I have this too for the systems_maintenances table:
(source: xooimage.com)

In a trigger, you don't refer to the table name of the table being affected. Instead, you refer to a proxie for it. That proxie depends on the database. In MySQL, it is new and old.
I suspect that you want something like this:
CREATE TRIGGER `deleteMaintenance` BEFORE DELETE ON `systems` FOR EACH ROW BEGIN
DELETE FROM maintenances m
WHERE maintenance_id IN (SELECT maintenance_id
FROM systems_maintenances sm
WHERE systems_maintenances.system_id = old.system_id
)
END;
There are other ways to express this logic, but this gives a good idea of the structure.
You can do essentially the same thing using cascading deletes, if you prefer. That way, you don't have to write triggers and can put the logic in the create table statement.

Related

Impala ACID table select ERROR: Operation not supported on transactional (ACID) table:

I'm using impala 3.4 directly with hive 3.1.
The problem is that if you create a general table in the hive and then select it in impala, an error occurs.
The error message is as follows:
Query: show tables
+----------+
| name |
+----------+
| customer |
| lineitem |
| nation |
| orders |
| part |
| partsupp |
| region |
| supplier |
| t |
+----------+
Fetched 9 row(s) in 0.02s
[host.cluster.com] default> select * from customer;
Query: select * from customer
Query submitted at: 2020-11-20 09:56:12 (Coordinator: http://host.cluster.com:25000)
ERROR: AnalysisException: Operation not supported on transactional (ACID) table: default.customer
In the hive, the acid table and the orc table are only concerned with whether to delete or update, but I knew that selection is common.
In fact, the select statement is normally executed through hive jdbc. Only impala would like to help you understand why this error occurs.
I solved this problem. It was confirmed that the table created through Hive in impala operates normally.
There are two possible causes:
Connect impala built with Hive2 to Hive 3 databases.
When creating a Hive Table that I did not recognize, set the default flag related to ACID.
This version can't read ACID table wich are created by Hive. Hive creates ACID table by default.

SQLite unique constraint on multiple column without order

I need help on a problem in my table definitions : I have a table which will be defined, for example, like this :
id, primary key
friend0_id, foreign key on table users
friend1_id, foreign key on table users
The problem is I do not want to have multiple times the couple (friend0_id, friend1_id), whatever the order the are in the table.
I tried to define an UNIQUE constraint on the couple (friend0_id, friend1_id), but the columns order defined in the constraint (here friend0_id, THEN friend1_id) matters. So :
| id | friend0_id | friend1_id |
|----|------------|------------|
| 1 | 3 | 4 | -> OK
| 2 | 4 | 3 | -> OK, as the columns order in index matters
| 3 | 3 | 4 | -> Not OK, constraint prevent this
I would like the id 2 and 3 in the example to be disallowed, but I can't figure how. Do you have some tips for me ?
Thank you,
naccyde
As #mu too short mentioned, the way is to use (greatest(friend0_id, friend1_id), least(friend0_id, friend1_id)), so, now I have a working 2 columns order free unique constraint. I did it in SQLite this way (which could not be the better) :
Create a trigger which set min(friend0_id, friend1_id) to friend0 and max(friend0_id, friend1_id) to friend1 :
CREATE TRIGGER friend_fixed_id_order_trigger
AFTER INSERT ON friends
BEGIN UPDATE friends
SET
friend0_id = min(NEW.friend0_id, NEW.friend1_id),
friend1_id = max(NEW.friend0_id, NEW.friend1_id)
WHERE friends.id = NEW.id;
END
Then, set a unique constraint on the couple (friend0_id, friend1_id) :
CREATE UNIQUE INDEX `friends_unique_relation_index`
ON `contacts` (`friend0_id` ,`friend1_id`)
And it works !
EDIT : If someone need this tip, do not forget to create an update trigger too, otherwise an update request could break the mechanism.

SQLITE: Transaction to check constraints after commit

I'm currently working on an sqlite table where I have to do the following:
ID | Name | SortHint
---|-------|---------
0 | A | 1
1 | B | 2
2 | C | 3
ID is the primary key and SortHint is a column with the UNIQUE-constaint. What I have to do is to modify the table, for example:
ID | Name | SortHint
---|-------|---------
0 | A | 3
1 | B | 1
2 | C | 2
The Problem: Because of the UNIQUE I can't simply update one row after another. I tried:
BEGIN TRANSACTION;
UPDATE MyTable SET SortHint = 3 WHERE ID= 0;
...
COMMIT;
But the first update query immideatly fails with:
UNIQUE constraint failed: MyTable.SortHint Unable to fetch row
So, is there a way to "disable" the unique constaint for a transaction and only check all of them once the transaction is committed?
Notes:
I can't modify the table
It works if I only use SortHint values that are not already in the table
I know how to "workaround" this problem, but I would like to know if there is a way to do this as described above
One possibility is to drop the unique constraint and then add it again. That is a little bit expensive, though.
Another would be to set the values to negative values:
UPDATE MyTable
SET SortHInt = - SortHint;
UPDATE MyTable
SET SortHint = 3
WHERE ID = 0;
. . .
If you cannot modify the table, you are not able to remove the constraint.
A workaround could be to change the SortHint to a range that is not in use.
For example you could add 10,000 to all of them. Commit.
Then change to the right number at once which have become free now.
Maybe test afterwards that no numbers of 10,000 or higher exist anymore.

error while creating a sqlite trigger

I have these tables:
+-------------------------+
| Movies |
+-----+--------+----------+
| _id | title | language |
+--+--+--------+----------+
|
+-------------------------+
|
+----------------------------------+
| Movie_Cast |
+------------+----------+----------+
| id | actor_id | movie_id |
+------------+-----+----+----------+
|
+-------------+
|
+-------------------+
| Actors |
+----------+--------+
| actor_id | name |
+----------+--------+
What i'm trying to do is to delete a movies row, delete also the related rows from the junction table (movie_cast). And finally delete, from actors table, all the rows that are not referenced in the movie_cast table.
this is the tables schema:
create table movies (_id INTEGER PRIMARY KEY, title TEXT, language TEXT);
create table movie_cast (id INTEGER PRIMARY KEY,
actor_id INTEGER REFERENCES actors(actor_id) ON DELETE RESTRICT,
movie_id INTEGER REFERENCES movies(_id) ON DELETE CASCADE);
create table actors (actor_id INTEGER PRIMARY KEY, actor TEXT UNIQUE);
right now, when the user deletes a movies entry, movie_cast rows referencing the movies._id are also deleted. (i had some troubles with that, but then i used "PRAGMA foreign_keys = ON;" ) so far so good! To delete the actors rows, i thought i could create a trigger that tries to delete actors entries based on the movie_cast.actor_id we just deleted, but since i'm using "ON DELETE RESTRIC", if the actor has still a reference it would abort the delete.
But i'm not even being able to prove it, because i'm getting an error when creating the trigger:
CREATE TRIGGER Delete_Actors AFTER DELETE ON movie_cast
FOR EACH ROW
BEGIN
DELETE FROM actors WHERE actors.actor_id = OLD.actor_id;
END;
SQL Error [1]: [SQLITE_ERROR] SQL error or missing database (near "actor_id": syntax error)
[SQLITE_ERROR] SQL error or missing database (near "actor_id": syntax error)
It seems, it doesn't know what OLD is. What am i doing wrong here?
UPDATE:
It looks like a sqlite configuration problem. I'm using DBeaver SQLite 3.8.2, and it seems to be a problem with the temporary file, but to be honest i don't know how to fix it even reading the possible solution:
It's failing to create the temporary file required for a statement journal.
It's likely any statement that uses a temporary file will fail.
http://www.sqlite.org/tempfiles.html
One way around the problem would be to configure SQLite not to use
temp files using "PRAGMA temp_store = memory;".
Or ensure that the environment variable SQLITE_TMPDIR is set to
the path of a writable directory. See also:
http://www.sqlite.org/c3ref/temp_directory.html
So, I am going to assume it works and try it directly on my android app.
It was something really s****p. For DBeaver the trigger creation is a complex-statement, and delimiters were not working either, so it was needed to select the whole statement then press ctrl+enter.
Anyway, the statement works. But for a better results I got rid of "ON DELETE RESTRICT" from movie_cast.actor_id. and created a conditional trigger, that executes the delete from actors table, only when there are no more actor_ids equal to the one just deleted(OLD):
CREATE TRIGGER Delete_Actors
AFTER DELETE ON movie_cast
FOR EACH ROW
WHEN (SELECT count(id) FROM movie_cast WHERE actor_id = OLD.actor_id) = 0
BEGIN
DELETE FROM actors WHERE actors.actor_id = OLD.actor_id;
END;

MySQL data version control

Is there any way to setup MySQL to every time a row is changed, then a row to another table/database is created with what the data was originally? (with time stamping)
If so how would I go about doing it?
E.g.
UPDATE `live_db`.`people`
SET `live_db`.`people`.`name` = 'bob'
WHERE `id` = 1;
Causes this to happen before the update:
INSERT INTO `changes_db`.`people`
SELECT *
FROM `live_db`.`people`
WHERE `live_db`.`people`.`id` = 1;
And if you did it again it would result in something like this:
`live_db`.`people`
+----+-------+---------------------+
| id | name | created |
+----+-------+---------------------+
| 1 | jones | 10:32:20 12/06/2010 |
+----+-------+---------------------+
`changes_db`.`people`
+----+-------+---------------------+
| id | name | updated |
+----+-------+---------------------+
| 1 | billy | 12:11:25 13/06/2010 |
| 1 | bob | 03:01:54 14/06/2010 |
+----+-------+---------------------+
The live DB needs to have a created time stamp on the rows, and the changes DB needs to have a time stamp of when the live DB row was updated.
The changes DB will also have no primary keys and foreign key constraints.
I'm using InnoDB and MySQL 5.1.49 but can upgrade if required.
Use a Trigger
MySQL support for triggers started with MySQL version 5.0.2.
You can create a trigger:
DELIMITER \\
CREATE TRIGGER logtrigger BEFORE UPDATE ON live_db.people
FOR EACH ROW BEGIN
INSERT INTO changes_db.people(id,name,updated) VALUES(OLD.id,OLD.name,now());
END;
\\
This is how I ended up doing it
DELIMITER |
# Create the log table
CREATE TABLE IF NOT EXISTS `DB_LOG`.`TABLE`
LIKE `DB`.`TABLE`|
# Remove any auto increment
ALTER TABLE `DB_LOG`.`TABLE` CHANGE `DB_LOG`.`TABLE`.`PK` `DB_LOG`.`TABLE`.`PK` INT UNSIGNED NOT NULL|
# Drop the primary keys
ALTER TABLE `DB_LOG`.`TABLE` DROP PRIMARY KEY|
#Create the trigger
DROP TRIGGER IF EXISTS `DB`.`update_TABLE`|
CREATE TRIGGER `DB`.`update_TABLE` BEFORE UPDATE ON `DB`.`TABLE` FOR EACH ROW
BEGIN
INSERT INTO `DB_LOG`.`TABLE`
SELECT `DB`.`TABLE`.*
FROM `DB`.`TABLE`
WHERE `DB`.`TABLE`.`PK` = NEW.`PK`;
END|
DELIMITER ;
Sorry to comment on an old post, but I was looking to solve this exact problem! Thought I would share this information.
This outlines a solution perfectly:
http://www.hirmet.com/mysql-versioning-records-of-tables-using-triggers