insert trigger: issue with constraint - mysql

I'm trying to create trigger on customer-order database where each customer has several orders and each order has several items.
I'm planning to create a trigger to ensure that
the total number of all orders place by the same customer cannot
exceed 10000
How can create the insert trigger for above constraint.
Here is my SQL file with sample data provided.
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;
CREATE TABLE customers
(`id` int not null auto_increment primary key, `first_name` varchar(64), `last_name`varchar(64) );
INSERT INTO customers(`first_name`, `last_name`)VALUES('Jhon', 'Doe');
CREATE TABLE items
(`id` int not null auto_increment primary key,`item` varchar(64),`price` decimal(19,2));
INSERT INTO items(`item`, `price`)VALUES('Item1', 10.5),('Item2', 25);
CREATE TABLE orders
(`id` int not null auto_increment primary key, `date` date, `customer_id` int,`status` int not null default 1, -- 1 new constraint fk_customer_id foreign key (customer_id) references customers (id));
INSERT INTO orders(`date`, `customer_id`, `status`)VALUES(CURDATE(), 1, 1);
CREATE TABLE order_items(`id` int not null auto_increment primary key,
`order_id` int not null, `item_id` int not null, `quantity` decimal(19,3) not null, `price` decimal(19,3) not null,
constraint fk_order_id foreign key (order_id) references orders (id),
constraint fk_item_id foreign key (item_id) references items (id));
INSERT INTO order_items(`order_id`, `item_id`, `quantity`, `price`)VALUES
(1, 1, 2, 10.5),(1, 2, 4, 25);
;

Although Jahul's answer would technically work, here is alternative logic:
DELIMITER $$
CREATE TRIGGER `customer_orders_check`
BEFORE INSERT ON `orders` FOR EACH ROW
BEGIN
IF ((select count(*)
from `orders`
where a.customer_id = NEW.customer_id
) >= 10000 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Too many orders already';
END IF;
END;
$$
DELIMITER ;
That said, I would suggest an alternative approach. Counting up to 10,000 rows for each insert seems like a lot of work. Instead, keep the counter in the customers table, using an after insert trigger (and perhaps after update/delete as well). Then when inserting a new row, you can just check the count in customers.

This trigger will stop insert --
CREATE TRIGGER `customer_orders_check`
BEFORE INSERT ON `orders` FOR EACH ROW
BEGIN
IF exists(select count(*)
from `orders` a
where a.customer_id= NEW.customer_id
having count(*)>=10000 ) THEN
SET NEW.id = 1 ;
END IF;
END;

Related

Insert new row into a table with values from another table mysql

I'm new to triggers in MySQL, so sorry for any question that seems "really easy".
I have two tables: orders and orders_log
orders:
order_id
(...)
product_id
(...)
201
(...)
103
(...)
oders_log:
log_id
action
table_name
action_time
product_id
NULL
NULL
NULL
NULL
NULL
I want to create a trigger that when we INSERT a new row into "orders" table, it will generate a new row into orders_log with the log_id = 1...2..3... etc; and product_id = to product_id in table "orders". So that the orders_log would look like this:
log_id
action
table_name
action_time
product_id
1
insert
orders
"now()"
103
I'm trying to do this code:
DROP TRIGGER IF EXISTS addrowlog;
DELIMITER $$
CREATE TRIGGER addrowlog
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
insert into orders_log (`log_id`, `action`, `table_name`, `action_time`, `product_id`)
VALUES (NEW.log_id, 'insert', 'orders', NOW(), NEW.product_id);
END$$
DELIMITER;
But is gaves this error: Error Code: 1054. Unknow column 'log_id' in 'NEW.
And even when i just do this code:
DROP TRIGGER IF EXISTS addrowlog;
DELIMITER $$
CREATE TRIGGER addrowlog
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
insert into orders_log (`log_id`, `action`, `table_name`, `action_time`, `product_id`)
VALUES (log_id, 'insert', 'orders', NOW(), product_id);
END$$
DELIMITER;
When i try to add a row into 'orders' it will give me error "Cannot add or update a child row: a foreign key constraint fails".
Can someone help me?
*EDIT:
Creation of the log table:
CREATE TABLE `orders_log` (
`log_id` INTEGER NOT NULL,
`action` VARCHAR(255) DEFAULT NULL,
`table_name` VARCHAR(255) DEFAULT NULL,
`action_time` TIME DEFAULT NULL,
`product_id` INTEGER NOT NULL,
PRIMARY KEY (`log_id`)
);
(trigger created in the middle)
plus
ALTER TABLE `orders_log`
ADD CONSTRAINT `fk_orders_log_3`
FOREIGN KEY (`product_id`)
REFERENCES `product` (`product_id`)
ON DELETE RESTRICT
ON UPDATE CASCADE;
```*
After adding the auto_increment, you can remove the log_id from your insert or add NULL as value
CREATE TABLe orders (product_id int)
CREATE TABLE `orders_log` (
`log_id` INTEGER NOT NULL AUTO_INCREMENT,
`action` VARCHAR(255) DEFAULT NULL,
`table_name` VARCHAR(255) DEFAULT NULL,
`action_time` TIME DEFAULT NULL,
`product_id` INTEGER NOT NULL,
PRIMARY KEY (`log_id`)
);
CREATE TRIGGER addrowlog
AFTER INSERT ON orders
FOR EACH ROW
BEGIN
insert into orders_log ( `action`, `table_name`, `action_time`, `product_id`)
VALUES ( 'insert', 'orders', NOW(), new.product_id);
END
INSERt INTO orders VALUEs(1)
SELECT * FROM orders_log
log_id
action
table_name
action_time
product_id
1
insert
orders
12:10:43
1
fiddle

MYSQL BETWEEN operator [duplicate]

I am having trouble with this table
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`meetid`,`pid`),
CONSTRAINT `participants_ibfk_1` FOREIGN KEY (`meetid`) REFERENCES `Meetings` (`meetid`) ON DELETE CASCADE
CONSTRAINT `participants_ibfk_2` CHECK (status IN ('a','d','u'))
CONSTRAINT `participants_ibfk_3` CHECK (pid IN (SELECT name FROM Rooms) OR pid IN (SELECT userid FROM People))
);
I want to have a foreign key constraint, and that works. Then, I also want to add a constraint to the attribute status so it can only take the values 'a', 'd' and 'u'. It is not possible for me to set the field as Enum or set.
Can anyone tell me why this code does not work in MySQL?
CHECK constraints are not supported by MySQL. You can define them, but they do nothing (as of MySQL 5.7).
From the manual:
The CHECK clause is parsed but ignored by all storage engines.
The workaround is to create triggers, but they aren't the easiest thing to work with.
If you want an open-source RDBMS that supports CHECK constraints, try PostgreSQL. It's actually a very good database.
I don't understand why nobody here has mentioned that VIEW WITH CHECK OPTION can be a good alternative to the CHECK CONSTRAINT in MySQL:
CREATE VIEW name_of_view AS SELECT * FROM your_table
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION;
There is a doc on the MySQL site: The View WITH CHECK OPTION Clause
DROP TABLE `Participants`;
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL check (status IN ('a','d','u')),
PRIMARY KEY (`meetid`,`pid`)
);
-- should work
INSERT INTO `Participants` VALUES (1,1,'a');
-- should fail but doesn't because table check is not implemented in MySQL
INSERT INTO `Participants` VALUES (2,1,'x');
DROP VIEW vParticipants;
CREATE VIEW vParticipants AS
SELECT * FROM Participants WHERE status IN ('a','d','u')
WITH CHECK OPTION;
-- should work
INSERT INTO vParticipants VALUES (3,1,'a');
-- will fail because view uses a WITH CHECK OPTION
INSERT INTO vParticipants VALUES (4,1,'x');
P.S.: Keep in mind that your view should be updatable! See MySQL Updatable Views
(thanks Romeo Sierra for clarification in comments).
Beside triggers, for simple constraints like the one you have:
CONSTRAINT `participants_ibfk_2`
CHECK status IN ('a','d','u')
you could use a Foreign Key from status to a Reference table (ParticipantStatus with 3 rows: 'a','d','u' ):
CONSTRAINT ParticipantStatus_Participant_fk
FOREIGN KEY (status)
REFERENCES ParticipantStatus(status)
Starting with version 8.0.16, MySQL has added support for CHECK constraints:
ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
CASE
WHEN DTYPE = 'Post'
THEN
CASE
WHEN content IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
CASE
WHEN DTYPE = 'Announcement'
THEN
CASE
WHEN validUntil IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
Previously, this was only available using BEFORE INSERT and BEFORE UPDATE triggers:
CREATE
TRIGGER post_content_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER post_content_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
Here is a way of getting the checks you wanted quickly and easily:
drop database if exists gtest;
create database if not exists gtest;
use gtest;
create table users (
user_id integer unsigned not null auto_increment primary key,
username varchar(32) not null default '',
password varchar(64) not null default '',
unique key ix_username (username)
) Engine=InnoDB auto_increment 10001;
create table owners (
owner_id integer unsigned not null auto_increment primary key,
ownername varchar(32) not null default '',
unique key ix_ownername (ownername)
) Engine=InnoDB auto_increment 5001;
create table users_and_owners (
id integer unsigned not null primary key,
name varchar(32) not null default '',
unique key ix_name(name)
) Engine=InnoDB;
create table p_status (
a_status char(1) not null primary key
) Engine=InnoDB;
create table people (
person_id integer unsigned not null auto_increment primary key,
pid integer unsigned not null,
name varchar(32) not null default '',
status char(1) not null,
unique key ix_name (name),
foreign key people_ibfk_001 (pid) references users_and_owners(id),
foreign key people_ibfk_002 (status) references p_status (a_status)
) Engine=InnoDB;
create or replace view vw_users_and_owners as
select
user_id id,
username name
from users
union
select
owner_id id,
ownername name
from owners
order by id asc
;
create trigger newUser after insert on users for each row replace into users_and_owners select * from vw_users_and_owners;
create trigger newOwner after insert on owners for each row replace into users_and_owners select * from vw_users_and_owners;
insert into users ( username, password ) values
( 'fred Smith', password('fredSmith')),
( 'jack Sparrow', password('jackSparrow')),
( 'Jim Beam', password('JimBeam')),
( 'Ted Turner', password('TedTurner'))
;
insert into owners ( ownername ) values ( 'Tom Jones'),( 'Elvis Presley'),('Wally Lewis'),('Ted Turner');
insert into people (pid, name, status) values ( 5001, 'Tom Jones', 1),(10002,'jack Sparrow',1),(5002,'Elvis Presley',1);

Creating custom (user defined) constraints in mysql [duplicate]

I am having trouble with this table
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`meetid`,`pid`),
CONSTRAINT `participants_ibfk_1` FOREIGN KEY (`meetid`) REFERENCES `Meetings` (`meetid`) ON DELETE CASCADE
CONSTRAINT `participants_ibfk_2` CHECK (status IN ('a','d','u'))
CONSTRAINT `participants_ibfk_3` CHECK (pid IN (SELECT name FROM Rooms) OR pid IN (SELECT userid FROM People))
);
I want to have a foreign key constraint, and that works. Then, I also want to add a constraint to the attribute status so it can only take the values 'a', 'd' and 'u'. It is not possible for me to set the field as Enum or set.
Can anyone tell me why this code does not work in MySQL?
CHECK constraints are not supported by MySQL. You can define them, but they do nothing (as of MySQL 5.7).
From the manual:
The CHECK clause is parsed but ignored by all storage engines.
The workaround is to create triggers, but they aren't the easiest thing to work with.
If you want an open-source RDBMS that supports CHECK constraints, try PostgreSQL. It's actually a very good database.
I don't understand why nobody here has mentioned that VIEW WITH CHECK OPTION can be a good alternative to the CHECK CONSTRAINT in MySQL:
CREATE VIEW name_of_view AS SELECT * FROM your_table
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION;
There is a doc on the MySQL site: The View WITH CHECK OPTION Clause
DROP TABLE `Participants`;
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL check (status IN ('a','d','u')),
PRIMARY KEY (`meetid`,`pid`)
);
-- should work
INSERT INTO `Participants` VALUES (1,1,'a');
-- should fail but doesn't because table check is not implemented in MySQL
INSERT INTO `Participants` VALUES (2,1,'x');
DROP VIEW vParticipants;
CREATE VIEW vParticipants AS
SELECT * FROM Participants WHERE status IN ('a','d','u')
WITH CHECK OPTION;
-- should work
INSERT INTO vParticipants VALUES (3,1,'a');
-- will fail because view uses a WITH CHECK OPTION
INSERT INTO vParticipants VALUES (4,1,'x');
P.S.: Keep in mind that your view should be updatable! See MySQL Updatable Views
(thanks Romeo Sierra for clarification in comments).
Beside triggers, for simple constraints like the one you have:
CONSTRAINT `participants_ibfk_2`
CHECK status IN ('a','d','u')
you could use a Foreign Key from status to a Reference table (ParticipantStatus with 3 rows: 'a','d','u' ):
CONSTRAINT ParticipantStatus_Participant_fk
FOREIGN KEY (status)
REFERENCES ParticipantStatus(status)
Starting with version 8.0.16, MySQL has added support for CHECK constraints:
ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
CASE
WHEN DTYPE = 'Post'
THEN
CASE
WHEN content IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
CASE
WHEN DTYPE = 'Announcement'
THEN
CASE
WHEN validUntil IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
Previously, this was only available using BEFORE INSERT and BEFORE UPDATE triggers:
CREATE
TRIGGER post_content_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER post_content_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
Here is a way of getting the checks you wanted quickly and easily:
drop database if exists gtest;
create database if not exists gtest;
use gtest;
create table users (
user_id integer unsigned not null auto_increment primary key,
username varchar(32) not null default '',
password varchar(64) not null default '',
unique key ix_username (username)
) Engine=InnoDB auto_increment 10001;
create table owners (
owner_id integer unsigned not null auto_increment primary key,
ownername varchar(32) not null default '',
unique key ix_ownername (ownername)
) Engine=InnoDB auto_increment 5001;
create table users_and_owners (
id integer unsigned not null primary key,
name varchar(32) not null default '',
unique key ix_name(name)
) Engine=InnoDB;
create table p_status (
a_status char(1) not null primary key
) Engine=InnoDB;
create table people (
person_id integer unsigned not null auto_increment primary key,
pid integer unsigned not null,
name varchar(32) not null default '',
status char(1) not null,
unique key ix_name (name),
foreign key people_ibfk_001 (pid) references users_and_owners(id),
foreign key people_ibfk_002 (status) references p_status (a_status)
) Engine=InnoDB;
create or replace view vw_users_and_owners as
select
user_id id,
username name
from users
union
select
owner_id id,
ownername name
from owners
order by id asc
;
create trigger newUser after insert on users for each row replace into users_and_owners select * from vw_users_and_owners;
create trigger newOwner after insert on owners for each row replace into users_and_owners select * from vw_users_and_owners;
insert into users ( username, password ) values
( 'fred Smith', password('fredSmith')),
( 'jack Sparrow', password('jackSparrow')),
( 'Jim Beam', password('JimBeam')),
( 'Ted Turner', password('TedTurner'))
;
insert into owners ( ownername ) values ( 'Tom Jones'),( 'Elvis Presley'),('Wally Lewis'),('Ted Turner');
insert into people (pid, name, status) values ( 5001, 'Tom Jones', 1),(10002,'jack Sparrow',1),(5002,'Elvis Presley',1);

Cannot create trigger

I am just want to create after insert trigger to insert a new row in history table. Why am I getting an error when I run the query?
orders
create table orders
(
id int auto_increment
primary key,
id_user int not null,
picture_name varchar(100) not null,
time date not null,
constraint FK_USER
foreign key (id_user) references stef.users (id)
)
;
create index FK_USER_idx
on orders (id_user)
;
history
create table history
(
id int auto_increment
primary key,
id_order int not null,
id_action int not null,
time date not null,
constraint FK_ORDER
foreign key (id_order) references stef.orders (id),
constraint FK_ACTION
foreign key (id_action) references stef.actions (id)
)
;
create index FK_ORDER_idx
on history (id_order)
;
create index FK_ACTION_idx
on history (id_action)
;
my trigger...
CREATE TRIGGER orders_AFTER_INSERT
AFTER INSERT ON stef.orders
FOR EACH ROW
BEGIN
INSERT INTO history('id_order', 'id_action', 'time')
VALUES (NEW.id, 1, NOW());
END;
I am just want to create after insert trigger to insert a new row in history table. Why am I getting an error when I run the query?
Try this
DELIMITER $$
CREATE TRIGGER orders_AFTER_INSERT
AFTER INSERT ON stef.orders
FOR EACH ROW
BEGIN
INSERT INTO history(`id_order`, `id_action`, `time`)
VALUES (NEW.id, 1, NOW());
END$$
DELIMITER ;
You need to temporarily override the delimiter so MySQL can differentiate between the end of a statement within the body of a trigger (or procedure, or function) and the end of the body.
Edit: Single quotes (') are only ever used to denote string values, for field names use the ` (or in some configurations the ")
CREATE TRIGGER orders_AFTER_INSERT
AFTER INSERT ON stef.orders
FOR EACH ROW
BEGIN
INSERT INTO stef.history()
VALUES (null, NEW.id, 1, NOW());
END

How do I add a custom CHECK constraint on a MySQL table?

I am having trouble with this table
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`meetid`,`pid`),
CONSTRAINT `participants_ibfk_1` FOREIGN KEY (`meetid`) REFERENCES `Meetings` (`meetid`) ON DELETE CASCADE
CONSTRAINT `participants_ibfk_2` CHECK (status IN ('a','d','u'))
CONSTRAINT `participants_ibfk_3` CHECK (pid IN (SELECT name FROM Rooms) OR pid IN (SELECT userid FROM People))
);
I want to have a foreign key constraint, and that works. Then, I also want to add a constraint to the attribute status so it can only take the values 'a', 'd' and 'u'. It is not possible for me to set the field as Enum or set.
Can anyone tell me why this code does not work in MySQL?
CHECK constraints are not supported by MySQL. You can define them, but they do nothing (as of MySQL 5.7).
From the manual:
The CHECK clause is parsed but ignored by all storage engines.
The workaround is to create triggers, but they aren't the easiest thing to work with.
If you want an open-source RDBMS that supports CHECK constraints, try PostgreSQL. It's actually a very good database.
I don't understand why nobody here has mentioned that VIEW WITH CHECK OPTION can be a good alternative to the CHECK CONSTRAINT in MySQL:
CREATE VIEW name_of_view AS SELECT * FROM your_table
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION;
There is a doc on the MySQL site: The View WITH CHECK OPTION Clause
DROP TABLE `Participants`;
CREATE TABLE `Participants` (
`meetid` int(11) NOT NULL,
`pid` varchar(15) NOT NULL,
`status` char(1) DEFAULT NULL check (status IN ('a','d','u')),
PRIMARY KEY (`meetid`,`pid`)
);
-- should work
INSERT INTO `Participants` VALUES (1,1,'a');
-- should fail but doesn't because table check is not implemented in MySQL
INSERT INTO `Participants` VALUES (2,1,'x');
DROP VIEW vParticipants;
CREATE VIEW vParticipants AS
SELECT * FROM Participants WHERE status IN ('a','d','u')
WITH CHECK OPTION;
-- should work
INSERT INTO vParticipants VALUES (3,1,'a');
-- will fail because view uses a WITH CHECK OPTION
INSERT INTO vParticipants VALUES (4,1,'x');
P.S.: Keep in mind that your view should be updatable! See MySQL Updatable Views
(thanks Romeo Sierra for clarification in comments).
Beside triggers, for simple constraints like the one you have:
CONSTRAINT `participants_ibfk_2`
CHECK status IN ('a','d','u')
you could use a Foreign Key from status to a Reference table (ParticipantStatus with 3 rows: 'a','d','u' ):
CONSTRAINT ParticipantStatus_Participant_fk
FOREIGN KEY (status)
REFERENCES ParticipantStatus(status)
Starting with version 8.0.16, MySQL has added support for CHECK constraints:
ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
CASE
WHEN DTYPE = 'Post'
THEN
CASE
WHEN content IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
CASE
WHEN DTYPE = 'Announcement'
THEN
CASE
WHEN validUntil IS NOT NULL
THEN 1
ELSE 0
END
ELSE 1
END = 1
);
Previously, this was only available using BEFORE INSERT and BEFORE UPDATE triggers:
CREATE
TRIGGER post_content_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER post_content_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Post'
THEN
IF NEW.content IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Post content cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
CREATE
TRIGGER announcement_validUntil_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
IF NEW.DTYPE = 'Announcement'
THEN
IF NEW.validUntil IS NULL
THEN
signal sqlstate '45000'
set message_text = 'Announcement validUntil cannot be NULL';
END IF;
END IF;
END;
Here is a way of getting the checks you wanted quickly and easily:
drop database if exists gtest;
create database if not exists gtest;
use gtest;
create table users (
user_id integer unsigned not null auto_increment primary key,
username varchar(32) not null default '',
password varchar(64) not null default '',
unique key ix_username (username)
) Engine=InnoDB auto_increment 10001;
create table owners (
owner_id integer unsigned not null auto_increment primary key,
ownername varchar(32) not null default '',
unique key ix_ownername (ownername)
) Engine=InnoDB auto_increment 5001;
create table users_and_owners (
id integer unsigned not null primary key,
name varchar(32) not null default '',
unique key ix_name(name)
) Engine=InnoDB;
create table p_status (
a_status char(1) not null primary key
) Engine=InnoDB;
create table people (
person_id integer unsigned not null auto_increment primary key,
pid integer unsigned not null,
name varchar(32) not null default '',
status char(1) not null,
unique key ix_name (name),
foreign key people_ibfk_001 (pid) references users_and_owners(id),
foreign key people_ibfk_002 (status) references p_status (a_status)
) Engine=InnoDB;
create or replace view vw_users_and_owners as
select
user_id id,
username name
from users
union
select
owner_id id,
ownername name
from owners
order by id asc
;
create trigger newUser after insert on users for each row replace into users_and_owners select * from vw_users_and_owners;
create trigger newOwner after insert on owners for each row replace into users_and_owners select * from vw_users_and_owners;
insert into users ( username, password ) values
( 'fred Smith', password('fredSmith')),
( 'jack Sparrow', password('jackSparrow')),
( 'Jim Beam', password('JimBeam')),
( 'Ted Turner', password('TedTurner'))
;
insert into owners ( ownername ) values ( 'Tom Jones'),( 'Elvis Presley'),('Wally Lewis'),('Ted Turner');
insert into people (pid, name, status) values ( 5001, 'Tom Jones', 1),(10002,'jack Sparrow',1),(5002,'Elvis Presley',1);