CHECK constrain in MySQL - mysql

I have a simple table in MySQL that contain two columns: Timestamp and floats. All I need is to ensure that new inserted value is greater than any other before in table. How can I achive that proper way?
CREATE TABLE IF NOT EXISTS `mydb`.`table1` (
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`read` FLOAT UNSIGNED NOT NULL,
PRIMARY KEY (`timestamp`))
ENGINE = InnoDB;

CREATE TRIGGER TRG_CHECKCONSTRAINT
BEFORE INSERT ON TABLE1
FOR EACH ROW
BEGIN
DECLARE msg varchar(255);
IF NOT new.READ > (SELECT MAX(READ) FROM TABLE1) THEN
SET msg = 'INVALID DATA'
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END

Use a BEFORE INSERT trigger. MySQL does not use CHECK constraints.

Related

Trigger before insert is not working

There is a "session" table, for it you need to write a trigger to check the date and time before inserting the data, if the date and time are greater than or equal to the current date and time, the value can be inserted into the table, otherwise the error message is displayed.
CREATE TABLE `seance` (
`idSeance` int(11) NOT NULL,
`Date/time` datetime NOT NULL,
`Hall_idHall` int(45) DEFAULT NULL,
`Hall_Theatre_idTheatre` int(45) DEFAULT NULL,
`Performance_idPerformance` int(45) NOT NULL,
`price` int(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TRIGGER `insert_seance` BEFORE INSERT ON `seance`
FOR EACH ROW BEGIN
IF (NEW.`Date/time` >= CURRENT_TIMESTAMP)
THEN
INSERT INTO seance
(`idSeance`, `Date/time`, `Hall_idHall`,
`Hall_Theatre_idTheatre`,`Performance_idPerformance`, `price`)
VALUES (NEW.`idSeance`,NEW.`Date/time`,NEW.`Hall_idHall`,
NEW.`Hall_Theatre_idTheatre`,NEW.`Performance_idPerformance`,NEW.`price`);
ELSE
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Error for updating values';
END IF;
END
I can not understand why it gives an error?
1442 - Can't update table 'seance' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
This is one of few mysql error messages which are crystal clear (IMHO). However - You don't need that INSERT statement. Just rise an error if the data is invalid. If the data is valid, you don't need to do anything in the trigger. The row will be just inserted.
CREATE TRIGGER `insert_seance` BEFORE INSERT ON `seance` FOR EACH ROW
BEGIN
IF (NEW.`Date/time` < CURRENT_TIMESTAMP)
THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Error for updating values';
END IF;
END

MySQL Insert/Update Trigger with AUTO_INCREMENT

So, I've got a table roughly as follows:
CREATE TABLE CUSTOMER (
CUSTID INT NOT NULL AUTO_INCREMENT,
NAME CHAR (45),
CONSTRAINT CUSTOMER_PRIMARY_KEY PRIMARY KEY (CUSTID))
AUTO_INCREMENT = 100;
I'm auto incrementing the CUSTID so that it's possible to simply insert a name and have it created with the next available CUSTID. However, I also want to ensure that it isn't possible to set the CUSTID value to zero, either on creation of the row or on update so I've constructed the following trigger:
DELIMITER $$
CREATE TRIGGER `custid_before_insert` BEFORE INSERT ON `CUSTOMER`
FOR EACH ROW
BEGIN
IF (NEW.CUSTID) <= 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Check constraint on CUSTOMER.CUSTID failed';
END IF;
END$$
CREATE TRIGGER `custid_before_update` BEFORE UPDATE ON `CUSTOMER`
FOR EACH ROW
BEGIN
IF (NEW.CUSTID) <= 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Check constraint on CUSTOMER.CUSTID failed';
END IF;
END$$
DELIMITER ;
Unfortunately in my blissful ignorance of how AUTO_INCREMENT worked, I've come to the conclusion that this is the wrong way to go about this. Trying to insert a customer with no CUSTID value is tripping the trigger causing the insert to fail which I presume is due to the value being a zero before insertion when AUTO_INCREMENT assigns it a value.
Would the best way to do this really be to change the trigger to occur after the insert and delete the row or is there a better way to do this to just throw an error?
The insert trigger is not needed.
From Auto_Increment
No value was specified for the AUTO_INCREMENT column, so MySQL
assigned sequence numbers automatically. You can also explicitly
assign 0 to the column to generate sequence numbers.
E.G.
create table t(id int auto_increment, primary key(id));
insert into t(id) values (0);
select id from t;
# 1
Update:
To allow the insert to complete when CUSTID is not specified,
INSERT INTO customer(name) VALUES('Chuck');
check for null in the trigger:
IF NEW.CUSTID IS NOT NULL AND NEW.CUSTID <= 0 THEN
Inserting '0' into an auto-increment column causes it to increment the same as inserting NULL, so you really neither need nor want the INSERT trigger. Try it with just the UPDATE trigger.

SQL constraint to make 2 columns not equal to each other

I have a table that has two columns to store id from another table. Column1 gets id from ABC table and Column2 also gets id from that table but letter is called parent ID, so with this information I know who is parent of who.
Now I want to create a constraint not to ever let both columns to get same id.
The following did not work:
ALTER TABLE id_parent_table
ADD CHECK (parent_id != main_id)
This is still allowing to insert two identical numbers.
This is now supported as of MySQL 8.0.16.
See https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html
mysql> create table id_parent_table (
-> main_id bigint unsigned not null,
-> parent_id bigint unsigned not null,
-> constraint columns_cannot_equal check (main_id <> parent_id)
-> );
Query OK, 0 rows affected (0.38 sec)
mysql> insert into id_parent_table (main_id, parent_id) values (1, 1);
ERROR 3819 (HY000): Check constraint 'columns_cannot_equal' is violated.
Apparently, MySQL does not support check constraints. To quote the online reference:
The CHECK clause is parsed but ignored by all storage engines.
You could, alternatively, use a trigger to fail such an insert or update:
EDIT: MySQL doesn't support a single trigger on two events, so you'd have to have two different triggers:
delimiter //
CREATE TRIGGER id_parent_table_check_insert_trg
BEFORE INSERT ON id_parent_table
FOR EACH ROW
BEGIN
DECLARE msg varchar(255);
IF new.parent_id = new.main_id THEN
SET msg = 'parent_id and main_id should be different';
SIGNAL SQLSTATE '45000' SET message_text = msg;
END IF;
END
//
CREATE TRIGGER id_parent_table_check_update_trg
BEFORE UPDATE ON id_parent_table
FOR EACH ROW
BEGIN
DECLARE msg varchar(255);
IF new.parent_id = new.main_id THEN
SET msg = 'parent_id and main_id should be different';
SIGNAL SQLSTATE '45000' SET message_text = msg;
END IF;
END
//

MySQL signal duplicate key error

I have a table, which includes an ENUM field. I would like for a particular value of ENUM to require uniqueness with the reference ID column. So let's say I have this:
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`type` ENUM('single','multi') NOT NULL,
`refid` INT UNSIGNED NOT NULL,
`extra` TEXT,
PRIMARY KEY (`id`)
I want (type,refid) to be a unique key, but only if type is single. This can't be done with conventional keys, so I figured I would use a Trigger to detect insertion of a row, check if type='single', look for a row with type='single' and refid=new.refid, and throw a duplicate entry error if one is found.
I'm using MySQL 5.5, so SIGNAL SQLSTATE is available to me. Can I use this to fire a Duplicate Key error in order to process the ON DUPLICATE KEY UPDATE part of the query, and if so, how?
As an alternative, I could update the row in the Trigger and return a generic error condition, but I think it would be nicer (or at least more intuitive) to have ON DUPLICATE KEY UPDATE work.
REPLACE INTO. Derp! Forgot all about that.
Try below trigger. I am not that good in writing triggers. I have not executed the code below. You can use this as a prototype.
CREATE TRIGGER checkDuplicateEntry
BEFORE INSERT OR UPDATE OF type, ref_id ON employees
DECLARE #duplicateCount INT;
FOR EACH ROW
IF ( new.type <> 'single' )
BEGIN
#duplicateCount = count(*) from yourTableName where type = 'single' AND refid = new.refid
END;
IF ( duplicateCount > 0 )
BEGIN
SIGNAL SQLSTATE VALUE '99999'
SET MESSAGE_TEXT = 'Duplicate Entry';
END

Using a check contraint in MySQL for controlling string length

I'm tumbled with a problem!
I've set up my first check constraint using MySQL, but unfortunately I'm having a problem. When inserting a row that should fail the test, the row is inserted anyway.
The structure:
CREATE TABLE user (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
uname VARCHAR(10) NOT NULL,
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
mail VARCHAR(50) NOT NULL,
PRIMARY KEY (id),
CHECK (LENGTH(fname) > 30)
);
The insert statement:
INSERT INTO user VALUES (null, 'user', 'Fname', 'Lname', 'mail#me.now');
The length of the string in the fname column should be too short, but it's inserted anyway.
I'm pretty sure I'm missing something basic here.
MySQL doesn't enforce CHECK constraints, on any engine.
Which leads me to ask, why would you declare the fname column as VARCHAR(50), but want to enforce that it can only be 30 characters long?
That said, the only alternative is to use a trigger:
CREATE TRIGGER t1 BEFORE INSERT ON user
FOR EACH ROW BEGIN
DECLARE numLength INT;
SET numLength = (SELECT LENGTH(NEW.fname));
IF (numLength > 30) THEN
SET NEW.col = 1/0;
END IF;
END;
As mentioned above you have to use a trigger, MySQL doesn't support check, also when you have multiple statements inside your trigger block, like declaring variables or control flows, you need to start it with begin and end and enclose your trigger inside two delimiters:
Note: If you use MariaDB use // after the first delimiter and before the second delimiter, otherwise if you use MySQL use $$ instead.
delimiter //
create trigger `user_insert_trigger` before insert on `user` for each row
begin
declare maximumFnameLength int unsigned;
declare fNameLength int unsigned;
set maximumFnameLength = 30;
set fNameLength = (select length(new.fNameLength));
if (fNameLength > maximumFnameLength) then
signal sqlstate '45000'
set message_text = 'First name is more than 30 characters long.';
end if;
end
//
delimiter ;