set maximum value to a column - mysql

I have a table with a column (int type) called age. This column should hold maximun value 50. If it exceeds then it shouldn't update that row.
Means this column shold take values from 0 to 50.
If I try to update that to 51 then that shouldn't allow.
Could any one help....!

Try this:
CREATE TRIGGER check_trigger
BEFORE INSERT
ON table
FOR EACH ROW
BEGIN
IF NEW.age<0 OR NEW.age>50 THEN
CALL `Error: Wrong values for age`; -- this trick will throw an error
END IF;
END

create table test (
age tinyint not null ) engine = myisam;
delimiter //
drop trigger if exists max_num//
create trigger max_num before insert on test
for each row
begin
if new.age < 0 or new.age > 50 then
set new.age = null;
end if;
end//
delimiter ;
insert into test (age) values (100);
Make the same thing for update.

You could use CHECK constraint:
CREATE TABLE person (
Name VARCHAR(80),
Age INT CHECK (Age BETWEEN 5 and 50));

MySQL introduced check constraints in MySQL 8.0.16 and now the check constraints are enforced as you would reasonably expect.
See MySQL 8.0.16 introduced check constraints.
So, you can achieve your goal by altering your age column using the statement below.
ALTER TABLE `YOUR_TABLE_NAME` MODIFY `age` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 CHECK(`age` <= 50);

Related

How to insert data in a column with a trigger after data is inserted in a row?

I have a program in Laravel where after users register they need a badge number, I want that number to be generated randomly after they register in the database. I should use triggers but I struggle with syntax.
users table
id bigint(20)
name varchar(255)
surname varchar(255)
nr_legitimatie varchar(255)
I want that 'nr_legitimatie' field to be unique.
This is what I tried but with no success
Trigger
CREATE OR REPLACE TRIGGER numar_leg
AFTER INSERT ON users
FOR EACH ROW
DECLARE
legitimatie VARCHAR(191)
BEGIN
legitimatie =('
SELECT FLOOR(RAND() * 99999) AS random_num
FROM numbers_mst
WHERE "random_num" NOT IN (SELECT my_number FROM numbers_mst)
LIMIT 1' );
set `users`.`nr_legitimatie` = legitimatie;
END;
Here's an example of a MySQL BEFORE INSERT trigger that assigns a value to the nr_legitimatie column.
DELIMITER $$
DROP TRIGGER numar_leg$$
CREATE TRIGGER numar_leg
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
DECLARE li_nrn BIGINT DEFAULT NULL;
DECLARE li_cnt BIGINT DEFAULT 1;
WHILE li_cnt > 0 DO
-- generate a new random number
SELECT FLOOR(RAND()*99999) AS nrn INTO li_nrn;
-- check if the new random number is already used
SELECT COUNT(1) INTO li_cnt FROM users u WHERE u.nr_legitimatie = li_nrn;
END WHILE;
SET NEW.nr_legitimatie := li_nrn;
END$$
DELIMITER ;
Note that this does not guarantee that the value assigned to the nr_legitimatie will be unique, because the code in the trigger is subject to a race condition. There is potential for two (or more) simultaneous sessions to each discover the same random number is not yet "unused", and each session will use it. (The check for an existing value precedes the assignment to the column.)
If we want to guarantee uniqueness, we should add a UNIQUE constraint (UNIQUE KEY) on the column in the users table.
We can also use a separate table to track the numbers that are used, with a UNIQUE constraint on the column, we can attempt inserts, and catch the error when an attempt to insert a duplicate is made.
If we introduce a tracking table, e.g.
CREATE TABLE nrn (nrn BIGINT PRIMARY KEY) ;
Then we can avoid the race condition, making the test for existing duplicate and reservation of the new value at the same time. Something like this:
DELIMITER $$
CREATE TRIGGER numar_leg
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
DECLARE li_nrn BIGINT DEFAULT NULL;
DECLARE li_dup BIGINT DEFAULT 1;
DECLARE CONTINUE HANDLER FOR 1062 SET li_dup := 1;
WHILE li_dup > 0 DO
SELECT FLOOR(RAND()*99999) AS nrn INTO li_nrn;
SET li_dup := 0;
INSERT INTO nrn (nrn) VALUES (li_nrn);
END WHILE;
SET NEW.nr_legitimatie := li_nrn;
END$$
DELIMITER ;
The edge case here is the trigger is executed, a new random number is generated and reserved, but the insert into the users table fails for some reason, and we don't issue a ROLLBACK. If we issue a ROLLBACK, then our new random number reservation will also be rolled back (unless nrn is a MyISAM table).

MySQL Before Delete trigger to avoid deleting multiple rows

I am trying to avoid deletion of more than 1 row at a time in MySQL by using a BEFORE DELETE trigger.
The sample table and trigger are as below.
Table test:
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
PRIMARY KEY (`id`));
INSERT INTO `test` (`id`, `a`, `b`)
VALUES (1, 1, 2);
INSERT INTO `test` (`id`, `a`, `b`)
VALUES (2, 3, 4);
Trigger:
DELIMITER //
DROP TRIGGER IF EXISTS prevent_multiple_deletion;
CREATE TRIGGER prevent_multiple_deletion
BEFORE DELETE ON test
FOR EACH STATEMENT
BEGIN
IF(ROW_COUNT()>=2) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Cannot delete more than one order per time!';
END IF;
END //
DELIMITER ;
This is still allowing multiple rows deletion. Even if I change the IF to >= 1, still allows the operation.
I my idea is to avoid operations such as:
DELETE FROM `test` WHERE `id`< 5;
Can you help me? I know that the current version of MySQL doesn't allow FOR EACH STATEMENT triggers.
Thank you!
Firstly, getting some syntax error(s) out of our way, from your original attempt:
Instead of FOR EACH STATEMENT, it should be FOR EACH ROW.
Since you have already defined the Delimiter to //; you need to use // (instead of ;) in the DROP TRIGGER IF EXISTS .. statement.
Row_Count() will have 0 value in a Before Delete Trigger, as no rows have been updated yet. So this approach will not work.
Now, the trick here is to use Session-level Accessible (and Persistent) user-defined variables. We can define a variable, let's say #rows_being_deleted, and later check whether it is already defined or not.
For Each Row runs the same set of statements for every row being deleted. So, we will just check whether the session variable already exists or not. If it does not, we can define it. So basically, for the first row (being deleted), it will get defined, which will persist as long as the session is there.
Now if there are more rows to be deleted, Trigger would be running the same set of statements for the remaining rows. In the second row, the previously defined variable would be found now, and we can simply throw an exception now.
Note that there is a chance that within the same session, multiple delete statements may get triggered. So before throwing exception, we need to set the #rows_being_deleted value back to null.
Following will work:
DELIMITER //
DROP TRIGGER IF EXISTS prevent_multiple_deletion //
CREATE TRIGGER prevent_multiple_deletion
BEFORE DELETE ON `test`
FOR EACH ROW
BEGIN
-- check if the variable is already defined or not
IF( #rows_being_deleted IS NULL ) THEN
SET #rows_being_deleted = 1; -- set its value
ELSE -- it already exists and we are in next "row"
-- just for testing to check the row count
-- SET #rows_being_deleted = #rows_being_deleted + 1;
-- We have to reset it to null, as within same session
-- another delete statement may be triggered.
SET #rows_being_deleted = NULL;
-- throw exception
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Cannot delete more than one order per time!';
END IF;
END //
DELIMITER ;
DB Fiddle Demo 1: Trying to delete more than row.
DELETE FROM `test` WHERE `id`< 5;
Result:
Query Error: Error: ER_SIGNAL_EXCEPTION: Cannot delete more than one
order per time!
DB Fiddle Demo 2: Trying to delete only one row
Query #1
DELETE FROM `test` WHERE `id` = 1;
Deletion successfully happened. We can check the remaining rows using Select.
Query #2
SELECT * FROM `test`;
| id | a | b |
| --- | --- | --- |
| 2 | 3 | 4 |

Conditional values in MySQL Trigger

I have a question about MySQL triggers—say I have the following table:
CREATE TABLE test (
id INT(6),
value_1 INT(6),
value_2 INT(6),
values_were_set BOOL
)
Now, every time I insert a value into this table I want to have a trigger check if value_1 and value_2 have been set. And if they are, it should set values_were_set to true.
NULL values are allowed.
How would I go about this? In the real table there are about ten columns that I want to check for, so I would fancy not to have to use a bunch of IF statements.
Maybe it's better to do it in the app?
Then trigger it is:
DELIMITER $$
CREATE TRIGGER value_check BEFORE INSERT ON test
FOR EACH ROW
BEGIN
IF NEW.value_1 IS NOT NULL AND NEW.value_2 IS NOT NULL THEN
SET NEW.values_were_set = 1;
ELSE
SET NEW.values_were_set = 0;
END IF;
END;
$$
Unfortunately yes, I think you would need a nasty if/else section in the trigger if you want to check multiple combinations of fields

how to insert concate value using trigger when new row inserted in mysql

In my schema I had two columns ,I am new to MySQL how to concatenate columns using Computed Column in mysql
ordertbl schema
Autoorderid int auto-increment
Orderid varchar(45)
I want to value orderid value insert when new row inserted
i had created the trigger for but this trigger is not firing when i am inserting the row
insert into order_master(customerID,ItemID,quantity,Unitprice,Total) values ('07961A','1000',6,5,30)
use ntc_sales; DELIMITER
$$ CREATE TRIGGER order_master_BINS BEFORE INSERT ON order_master FOR EACH ROW
SET NEW.OrderID = CONCAT('ORD' ,NEW.AutoOrderID) ; end;
create table
enter code here
CREATE TABLE Demo(ID INT PRIMARY KEY,
IDwithChar AS 'ORD' + RIGHT('0000000' + CAST(ID AS VARCHAR(10)), 6) PERSISTED,valuevar nvarchar(45)
)
This is showing syntax error in mysql how to create table as above schema in mysql
You can't really do this using a trigger in MySQL.
A BEFORE trigger is run before the auto increment value is set, so NEW.AutoOrderID will always be 0.
An AFTER trigger cannot update the same table as it is triggered on.
In other words, instead of triggering on an INSERT, creating the row using a stored procedure that does the insert/update in a single transaction is probably the best way to proceed.
EDIT: You could use a separate table for the sequence, but that would not guarantee that the order number is the same value as AutoOrderID, just a unique value.
CREATE TABLE order_sequence (
seq INT PRIMARY KEY AUTO_INCREMENT
);
CREATE TRIGGER order_master_BINS BEFORE INSERT ON order_master
FOR EACH ROW
BEGIN
INSERT INTO order_sequence VALUES (0);
SET NEW.OrderID = CONCAT('ORD', LAST_INSERT_ID());
END
An SQLfiddle to test the alternate solution with.

MySQL: Set to default value on update

Is it possible to set a column to its default value (or any specified value) on update when no value is specifically given in the statement? I was thinking that a trigger might accomplish this. Something like
IF ISNULL(NEW.column) THEN
NEW.column = value
END IF;
didn't work.
MySQL has function called DEFAULT(), which gets the default value from specified column.
UPDATE tbl SET col = DEFAULT(col);
MySQL Reference
UPDATE:
#JanTraenkner As far as I can tell, this is not possible. You can however make sure in your application code, that all columns are mentioned in your update statement and for those that do not have a value your use NULL as value. Then your trigger code is almost right, you just need to change it to
IF (NEW.column IS NULL) THEN
SET NEW.column = value
END IF;
Original answer:
I understood your question like, "set column to default value, if I don't specify the column in an update statement (which updates other columns from that table)".
To check with ISNULL() or col IS NULL doesn't work here, because when you don't specify it in the update statement it simply isn't there. There's nothing to check for.
I wrote this little example script which makes it work like I understood the question.
drop table if exists defvalue;
create table defvalue (id int auto_increment primary key, abc varchar(255) default 'default');
insert into defvalue (id) values (null);
insert into defvalue (id, abc) values (null, 'not_default_value');
insert into defvalue (id, abc) values (null, 'another_not_default_value');
drop trigger if exists t_defval;
delimiter $$
create trigger t_defval before update on defvalue
for each row
begin
set #my_def_value = (select default(abc) from defvalue limit 1);
if (new.abc = old.abc) then
set new.abc = #my_def_value;
end if;
end $$
delimiter ;
select * from defvalue;
update defvalue set id = 99 where id = 1;
select * from defvalue;
update defvalue set id = 98 where id = 2;
select * from defvalue;
I also had to save the default value of the column in a variable first because the function needs to know from which table. Unfortunately one can't specify that as parameter, not even as default(tablename.column).
All in all, please note, that this is rather a proof of concept. I'd recommend to solve this on application layer, not database layer. Having a trigger for this seems a bit dirty for me.