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
//
Related
doing my assignment on Databases. Working with MySQL, my task is to create database with several tables. One of them is the table of workers in which primary key is WId, which is the String of 16 A-Z and 0-9 elements. I need to make a constraint such that it is not possible to put there !##$%^ etc.
create table Worker ( WId char(16) primary key,
Name char(10),
Surname char(20),...);
Thanks.
You can always use the SIGNAL keyword to return an error:
EDIT 1:
Based on #Gordon_linoff comment: you would have to do both BEFORE INSERT and BEFORE UPDATE in case if you expect the Id to change.
CREATE TRIGGER myTrigger
BEFORE INSERT
ON worker
FOR EACH ROW
BEGIN
IF NOT (NEW.WId REGEXP '^[A-Za-z0-9]+$')
THEN
BEGIN
SIGNAL sqlstate '45000' set message_text = 'TADA!';
END;
END IF;
END;
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.
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.
I have a problem with the following sql code executed in MySQL Workbench 5.6. The table is orderly created, the trigger creation code is also run without errors. But when I try to run the both insert into statements I have an error Error Code: 1054. Unknown column 'Pass' in 'field list'. If I run the last select statements it is also runned as expected!?
I really can not imagine what is happening after running the trigger creation script!?
If I do not run the triger creation code before the insert into statements they are executed as expected and the data is inserted in the columns.
/*TASK 15: Write a SQL statement to create a table Users. Users should have username,
password, full name and last login time. Choose appropriate data types for the table fields.
Define a primary key column with a primary key constraint. Define the primary key column
as identity to facilitate inserting records. Define unique constraint to avoid repeating
usernames. Define a check constraint to ensure the password is at least 5 characters long.
*/
create table Users(
UserID int auto_increment not null,
Username nvarchar(50) not null,
Pass varchar(100) not null,
FullName nvarchar(100),
LastLoginTime datetime,
constraint PK_Users primary key(UserID),
constraint UK_Users_Username UNIQUE(Username),
constraint CH_Users_Password CHECK(length(users.Pass)>=5)
);
DELIMITER $$
CREATE TRIGGER `TR_BeforeInsert_Users`
BEFORE INSERT ON `users`
FOR EACH ROW
BEGIN
IF LENGTH(`Pass` ) < 5 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'check constraint on Pass failed';
END IF;
END$$
delimiter ;
Insert into Users(Username, Pass, FullName,lastlogintime) values('ttitto','alabala','Todor', now());
Insert into Users(Username, Pass, FullName,lastlogintime) values('ttitt','ala','Todor', now());
select length(Pass) from users;
Within triggers, one must reference columns with either the NEW or OLD pseudo-table prefix. In your case:
DELIMITER $$
CREATE TRIGGER `TR_BeforeInsert_Users`
BEFORE INSERT ON `users`
FOR EACH ROW
BEGIN
IF CHAR_LENGTH(NEW.Pass) < 5 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'check constraint on Pass failed';
END IF;
END$$
delimiter ;
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 ;