MySQL CHECK Constraint Emulation

Created with Sketch.

MySQL CHECK Constraint Emulation

Summary: in this tutorial, you will learn how to use emulate CHECK constraints in MySQL using triggers or views.

MySQL 8.0.16 fully implemented the SQL CHECK constraint. If you use MySQL 8.0.16 or later, check it out the CHECK constraint tutorial.

Emulating CHECK constraints using triggers

To emulate CHECK constraints in MySQL, you can use two triggers: BEFORE INSERT and BEFORE UPDATE.

First, create a new table named  parts for the demonstration:

CREATE TABLE IF NOT EXISTS parts (
part_no VARCHAR(18) PRIMARY KEY,
description VARCHAR(40),
cost DECIMAL(10 , 2 ) NOT NULL,
price DECIMAL(10,2) NOT NULL
);

Code language: SQL (Structured Query Language) (sql)

Next, create a stored procedure to check the values in the cost and price columns.

DELIMITER $CREATE PROCEDURE `check_parts`(IN cost DECIMAL(10,2), IN price DECIMAL(10,2))
BEGIN
IF cost < 0 THEN
SIGNAL SQLSTATE ‘45000’
SET MESSAGE_TEXT = ‘check constraint on parts.cost failed’;
END IF;

IF price < 0 THEN
SIGNAL SQLSTATE ‘45001’
SET MESSAGE_TEXT = ‘check constraint on parts.price failed’;
END IF;

IF price < cost THEN
SIGNAL SQLSTATE ‘45002’
SET MESSAGE_TEXT = ‘check constraint on parts.price & parts.cost failed’;
END IF;
END$
DELIMITER ;

Code language: SQL (Structured Query Language) (sql)

Then, create BEFORE INSERT and BEFORE UPDATE triggers. Inside the triggers, call the check_parts() stored procedure.

-- before insert
DELIMITER $
CREATE TRIGGER `parts_before_insert` BEFORE INSERT ON `parts`
FOR EACH ROW
BEGIN
CALL check_parts(new.cost,new.price);
END$
DELIMITER ;
-- before update
DELIMITER $
CREATE TRIGGER `parts_before_update` BEFORE UPDATE ON `parts`
FOR EACH ROW
BEGIN
CALL check_parts(new.cost,new.price);
END$
DELIMITER ;

Code language: SQL (Structured Query Language) (sql)

After that, insert a new row that satisfies all the following conditions:

  • cost > 0
  • And price > 0
  • And price  >= cost
INSERT INTO parts(part_no, description,cost,price)
VALUES('A-001','Cooler',100,120);

Code language: SQL (Structured Query Language) (sql)

1 row(s) affected

The INSERT statement invokes the BEFORE INSERT trigger and accepts the values.

The following INSERT statement fails because it violates the condition: cost > 0.

INSERT INTO parts(part_no, description,cost,price)
VALUES('A-002','Heater',-100,120);

Code language: SQL (Structured Query Language) (sql)

Error Code: 1644. check constraint on parts.cost failed

Code language: SQL (Structured Query Language) (sql)

The following INSERT statement fails because it violates the condition: price > 0.

INSERT INTO parts(part_no, description,cost,price)
VALUES('A-002','Heater',100,-120);

Code language: SQL (Structured Query Language) (sql)

Error Code: 1644. check constraint on parts.price failed

Code language: JavaScript (javascript)

The following INSERT statement fails because it violates the condition: price > cost.

INSERT INTO parts(part_no, description,cost,price)
VALUES('A-003','wiper',120,100);

Code language: SQL (Structured Query Language) (sql)

Let’s see what we are having now in the parts table.

SELECT * FROM parts;

Code language: SQL (Structured Query Language) (sql)

MySQL CHECK Constraint Emulation Example

The following statement attempt to update the cost to make it lower than the price:

UPDATE parts
SET price = 10
WHERE part_no = 'A-001';

Code language: SQL (Structured Query Language) (sql)

Error Code: 1644. check constraint on parts.price & parts.cost failed

Code language: SQL (Structured Query Language) (sql)

The statement was rejected.

So by using two triggers: BEFORE INSERT and BEFORE UPDATE, you are able to emulate CHECK constraints in MySQL.

Emulate CHECK constraints using views

The idea is to create a view WITH CHECK OPTION based on the underlying table. In the SELECT statement of the view definition, we select only valid rows that satisfy the CHECK conditions. Any insert or update against the view will be rejected if it causes the new row to not appear in the view.

First, drop the parts table to remove all the associated triggers and create a new table like the parts table but have a different name parts_data:

DROP TABLE IF EXISTS parts;CREATE TABLE IF NOT EXISTS parts_data (
part_no VARCHAR(18) PRIMARY KEY,
description VARCHAR(40),
cost DECIMAL(10,2) NOT NULL,
price DECIMAL(10,2) NOT NULL
);

Code language: SQL (Structured Query Language) (sql)

Next, create a view named parts based on the parts_data table. By doing this, we can keep the code of the applications that use the parts table remains intact. In addition, all the privileges to the old parts table remains unchanged.

CREATE VIEW parts AS
SELECT
part_no, description, cost, price
FROM
parts_data
WHERE
cost > 0 AND price > 0 AND price >= cost
WITH CHECK OPTION;

Code language: SQL (Structured Query Language) (sql)

Then, insert a new row into the parts_data table through the parts view:

INSERT INTO parts(part_no, description,cost,price)
VALUES('A-001','Cooler',100,120);

Code language: SQL (Structured Query Language) (sql)

It is accepted because the new row is valid which appears in the view.

After that, attempt to insert a new row that would not appear in the view.

INSERT INTO parts_checked(part_no, description,cost,price)
VALUES('A-002','Heater',-100,120);

Code language: SQL (Structured Query Language) (sql)

Error Code: 1369. CHECK OPTION failed 'classicmodels.parts_checked'

Code language: JavaScript (javascript)

In this tutorial, you have learned how to use triggers or views to emulate the CHECK constraints in MySQL.

Leave a Reply

Your email address will not be published. Required fields are marked *