Need comments on MySQL events - mysql

SET GLOBAL event_scheduler = ON;
CREATE TABLE question(
qid INT AUTO_INCREMENT PRIMARY KEY,
name CHAR(30) NOT NULL,
text CHAR(100) NOT NULL,
variation BOOLEAN NOT NULL,
url CHAR(100) NOT NULL UNIQUE,
expired TIMESTAMP NOT NULL
);
CREATE TABLE alternativ(
aid INT AUTO_INCREMENT PRIMARY KEY,
name CHAR(30) NOT NULL,
text CHAR(50) NOT NULL,
number_chosen INT,
qid INT NOT NULL
);
ALTER TABLE alternativ
ADD FOREIGN KEY (qid)
REFERENCES question(qid);
CREATE EVENT delete_expired
ON SCHEDULE
EVERY 1 DAY
DO
DELETE FROM alternativ WHERE alternativ.qid IN (SELECT qid FROM question WHERE question.expired<CURRENT_TIMESTAMP)
DELETE FROM question WHERE question.expired < CURRENT_TIMESTAMP;
My question is: Should this event work with the specified database? I have tried, but it dosen't seem to work. The idea is that the database itself will delete questions that has expired. Help would much be appreciated.

If you want to specify multiple statements within the event body, you will need to wrap them within a compound statement block such as BEGIN ... END (in order to make such a command work, one must configure one's client to use an alternative statement delimiter in order that it does not think the first encountered semicolon terminates the CREATE EVENT statement—in the mysql command-line tool, one can use the DELIMITER command):
DELIMITER ;;
CREATE EVENT ... DO BEGIN
DELETE ... ;
DELETE ... ;
END ;;
DELIMITER ;
That said, one can delete from multiple tables with a single DELETE command using the multiple-table syntax:
DELETE alternativ, question
FROM alternativ JOIN question USING (qid)
WHERE question.expired < CURRENT_TIMESTAMP
However, all that said, you might fare better specifying foreign key constraints that cascade record deletions:
FOREIGN KEY (qid) REFERENCES question(qid) ON DELETE CASCADE
Then, one only need DELETE the referenced record (i.e. in the question table) and MySQL will delete the referencing records (i.e. in the alternativ table) for you.

Related

Constant column value in MySQL table

I have a table in MySQL. I'd like to set a column value for a table to be a constant integer. How can I do this?
Unfortunately MySQL does not support SQL check constraints. You can
define them in your DDL query for compatibility reasons but they are
just ignored. You can create BEFORE INSERT and BEFORE UPDATE triggers
which either cause an error or set the field to its default value when
the requirements of the data are not met.
So here you can find a way around through MYSQL TRIGGER.
Sample Table:
DROP TABLE IF EXISTS `constantvaluetable`;
CREATE TABLE `constantvaluetable` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`constValue` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB;
Trigger:
DROP TRIGGER IF EXISTS trigger_const_check;
delimiter //
CREATE TRIGGER trigger_const_check BEFORE INSERT ON constantvaluetable
FOR EACH ROW
BEGIN
IF NEW.constValue <> 71 THEN
SIGNAL SQLSTATE '45000' SET message_text ='Only allowed value is 71';
END IF;
END //
delimiter ;
Test:
INSERT INTO constantvaluetable(constValue) VALUES(71);
INSERT INTO constantvaluetable(constValue) VALUES(66);
Result:
The first insert statement will succeed.
The second insert statement will fail. And the following error message will be shown:
[Err] 1644 - Only allowed value is 71
Note: Assuming your CONSTANT value is 71.
Do you really want to do this?
Would the following not suffice
Select Field1, field2, field3 , 5 as `ConstantField` from myTable
Although 71's trigger solution is the general purpose approach, since it can be used for more complicated conditions, in your case where you just want to check for a constant value, you can stay closer to database logic and add a foreign key to a table that just contains that one allowed value in it, e.g.
create table tbl_checkconst (constraintvalue int primary key);
insert into tbl_checkconst values (71);
alter table yourtable
add constraint fk_yourtable_constcheck
foreign key (column1)
references tbl_chechconst (constraintvalue);
It will actually add some overhead (since it will need to add an index), but would express your constraint in database logic, and your constant usually has a meaning that is in this way designed into the database model (although it is just 1 value now), and you (and any user with the correct permissions) can easily add more allowed values by adding it to the tbl_checkconst-table without modifying your trigger code.
And another reason I added it is that I guess you are really actually looking for a foreign key: In one of your comments you said you are trying to create a "double foreign key to a reference table". If I understand that correctly, you might want to use a composite foreign key, since you are able to combine columns for a foreign key:
alter table yourtable
add constraint fk_yourtable_col1col2
foreign key (column1, column2)
references your_reference_table (refcolumn1, refcolumn2);
You would just set up a CHECK constraint in your table when you set it up. Something like this is all you need in most DBMSs
CREATE someTable
(
someValue int(4) CHECK (someValue = 4)
)
However, with MySQL, CHECK constraints don't behave the same as they do in other DBMSs. The situation is a little more tricky. The answer seems to be here: https://stackoverflow.com/a/14248038/5386243

Mysql trigger on Delete to multiple tables (also error 1235)

I have 3 tables that are called:
character_
learned_skills
skills
"character_" contains certain informations on a list of characters, while the table "skills" contrains a list of skills.
the 3rd table is the list of the skills each character has learned.
However I want to able ones a character has been deleted from the character_ table, it also deletes the name of that character and the skills it has learned from the table "learned_skills".
I assume that a trigger is required in this situation. I know that the syntax is:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR REACH ROW tigger_statement;
However I can't figure out how the trigger_statement should look like.
CREATE TRIGGER delete_char_ AFTER DELETE ON character_ FOR REACH ROW trigger_statement
Is it enough with a sigle statement or does it require several statements and or cascade?
What would you do in this situation?
CREATE TABLE character_ (
Name_ varchar (30) NOT NULL,
Class varchar (30),
World_Type varchar (15),
Str integer ,
WS integer ,
BS integer ,
Fel integer ,
Per integer ,
Int_ integer ,
Agi integer ,
WP integer ,
Tough integer ,
PRIMARY KEY (Name_) ,
FOREIGN KEY (Class) REFERENCES Class(Class_name),
FOREIGN KEY (World_Type) REFERENCES World_Type(Name_) );
CREATE TABLE Skills (
SkillName varchar (30) NOT NULL,
Type_ varchar (30),
Characteristic varchar (30),
Descriptor varchar (30),
PRIMARY KEY (SkillName) );
CREATE TABLE Learned_Skills (
Character_Name varchar (30) NOT NULL,
Skill_Name varchar (40) NOT NULL,
PRIMARY KEY (Character_Name,Skill_Name),
FOREIGN KEY (Character_Name) REFERENCES character_(Name_),
FOREIGN KEY (Skill_Name) REFERENCES Talents(TalentName) );
UPDATE:
So I have had help to understand and make a DELETE trigger, but I have found out that need to create a multiple trigger on two tables, I know that its not possible to create a trigger on two with the same triggertime and event, but is there a way around it? What I need is the following:
DELIMITER //
CREATE TRIGGER delete_char_ AFTER DELETE ON character_
FOR EACH ROW begin
DELETE FROM learned_skills
WHERE learned_skills.Character_Name = old.Name_;
DELETE FROM learned_talents
WHERE learned_talents.Character_Name = old.Name_;
END;
//
DELIMITER ;
When I run this code I get error code:
1235, this version of mysql doesn't yet support 'multiple triggers with the samme action time and event for one table
Here is what it would look like:
CREATE TRIGGER delete_char_ AFTER DELETE ON character_
FOR EACH ROW
DELETE FROM learned_skills
WHERE learned_skills.Character_Name = old.Name_;
You will need to replace <field> with whatever the primary key is of the character_. This will delete anything from the learned_skills table that has the <field> of the character_ being deleted.

MySQL: INSERT .... ON DUPLICATE KEY UPDATE: affected-rows == 3?

The MySQL documentation states that when using INSERT ... ON DUPLICATE KEY UPDATE, the affected-rows value will be 1 when a record was inserted, 2 if an existing record was updated.
We're getting an affected-rows value of 3 when a record is updated, although I'm only seeing this when the updates are performed via MySQL calls using Connector-J from Java; when I invoke the stored procedure from the MySQL Workbench, I get the expected result of 2 rows updated.
Does anyone have any idea what this might mean? Is this perhaps a Connector-J annomaly? I'd be inclined to just run with it, but without a reasonable explanation, I'm left with concerns for my data integrity (which is, after all, one of the reasons to check the affected-rows value).
MySQL server version: 5.1.57; Connector-J version: 5.1.7 (Java 1.6)
Additional details:
This is the table being modified:
CREATE TABLE `UserContactProperty` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`UserContactId` int(11) NOT NULL,
`Property` varchar(45) NOT NULL,
`Value` tinytext,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `Contact-Property` (`UserContactId`,`Property`),
KEY `FK_UserContact` (`UserContactId`),
CONSTRAINT `FK_UserContact` FOREIGN KEY (`UserContactId`) REFERENCES `UserContact` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=28685 DEFAULT CHARSET=latin1
The stored procedure performing the insert/update is as follows:
CREATE PROCEDURE `setUserContactProperty`(
UID VARCHAR(50),
CID INT,
Prop VARCHAR(45),
Val TINYTEXT
)
BEGIN
INSERT INTO UserContactProperty ( UserContactId, Property, Value )
VALUES ( CID, Prop, Val )
ON DUPLICATE KEY UPDATE Value = Val, Date = CURRENT_TIMESTAMP;
END
It seems as a bug. please check the following link:
http://bugs.mysql.com/bug.php?id=46675
As reported there, the bug is related to another bug where the generated key list is wrong and the count is wrong too. (the second bug originated from here http://slava-technical.blogspot.co.il/2011/05/mysql-on-duplicate-key-update-breaks.html)
I think you need to find a workaround. probably by querying the database prior to inserting to see if the row with this key exists or not. or insert and catch duplicate key exception and then make the update in that case.

MySQL: Update a table in its own trigger

Apparently MySQL have the really annoying restriction of not being able to update a table inside a trigger defined for that same table.
I'm using MySQL version 5.1 and I get the error: "Can't update table in stored function/trigger because it is already used by statement which invoked this function/trigger".
What I have is this:
create table folder(
id int unsigned not null auto_increment PRIMARY KEY ,
name varchar(100) not null ,
parentId int unsigned not null
) ;
It's a hierarchical folder structure. A folder has a name and possibly a parent folder (if not then parentId is zero).
When a folder is deleted I need to change the parentId of all subfolders which were inside it, so that they don't become children of a nonexistent folder.
It's rather simple (almost trivial):
CREATE DEFINER=root#localhost TRIGGER onFolderDelete after delete ON folder
FOR EACH ROW update folder set parentId=0 where parentId=old.id ;
However, such a simple trigger is not allowed by MySQL because, as I said above, you cannot update a table inside its own trigger.
Is there any way of implementing such a trigger by emulating its effects in some way??
P.S.: Please dont suggest sending both statements in sequence (the DELETE and the UPDATE). That's obviously the last solution if nothing else is possible.
Edit:
I'm using MyISAM engine (performance reasons) so I can't use foreign keys.
Can't you add a foreign key with ON DELETE SET NULL (or DEFAULT) ?
UPDATE (DEFAULT is still not implemented;SET NULL is the only option...)
So you will have something like
create table folder(
id int unsigned not null auto_increment PRIMARY KEY ,
name varchar(100) not null ,
parentId int unsigned null ,
FOREIGN KEY(parentId) REFERENCES folder(id) ON UPDATE CASCADE ON DELETE SET NULL
) ;

Reverse of ON DELETE CASCADE

Suppose I have the following schema:
CREATE TABLE `users` (
`id` int(10) unsigned auto_increment,
`historyId` varchar(255),
PRIMARY KEY (`id`)
);
CREATE TABLE `histories` (
`id` int(10) unsigned auto_increment,
`history` TEXT,
PRIMARY KEY (`id`)
);
A User only ever has one History, and the purpose of not having histories point to users is that many other tables (not mentioned in this schema) also have histories.
What's the simplest way to make it so that deleting a User will also delete its History?
You can use trigger like this:
DELIMITER $$
CREATE TRIGGER delete_user_history_on_delete_user
AFTER DELETE ON `users`
FOR EACH ROW
BEGIN
DELETE FROM `histories` WHERE id = old.historyId;
END$$
DELIMITER ;
I don't think you can use a foreign key to cascade deletes here, because the data types don't match. You have VARCHAR(255) in one table, and INT(10) in the other. (What's up with that?)
I think you'll have to use either a trigger or a stored procedure, neither of which is entirely satisfactory. Triggers are theoretically the safest, in that client code can't sneak around them. (Client code could just avoid calling a stored procedure.) But there are APIs that don't activate MySQL triggers.
MySQL triggers are activated by SQL
statements only. They are not
activated by changes in tables made by
APIs that do not transmit SQL
statements to the MySQL Server
If User-histories it's a 1-1 relation you can put the constraint in the users table and not in the 'hisories' one