How to get column's DEFAULT in trigger? - mysql

I'd like one column's value to be forced to DEFAULT in trigger by some conditions.
In example below, if b IS NULL, a should be set with defined DEFAULT (that is 'SYSTEM').
CREATE TABLE `t_default` (
`n` VARCHAR(50) NOT NULL
, `a` VARCHAR(50) NOT NULL DEFAULT 'SYSTEM'
, `b` VARCHAR(50) NULL DEFAULT NULL
-- To moderators: please do not edit my formatting :)
);
DELIMITER //
CREATE TRIGGER `TRG_t_default_BeforeInsert` BEFORE INSERT ON `t_default` FOR EACH ROW BEGIN
IF NEW.b IS NULL THEN
SET NEW.a = DEFAULT(a);
END IF;
END
//
DELIMITER ;
Unfortunately, this gives error message "Unknown column 'a' in 'field list'" on insert:
INSERT INTO t_default (n) VALUES ('1');
I've found similar question, however providing table name or db + table name does not work as well:
CREATE TRIGGER `TRG_t_default_BeforeInsert` BEFORE INSERT ON `t_default` FOR EACH ROW BEGIN
IF NEW.b IS NULL THEN
SET NEW.a = DEFAULT(t_default.a);
-- SET NEW.a = DEFAULT(test.t_default.a);
END IF;
END
In this case message is slightly different: "Unknown table 't_default' in field list"
Also, I tried to use back quotes around column name with no success.
So, is it possible to get column DEFAULT in trigger at all? I'm using MySQL 5.7.
Thanks.
P.S. Sure, I know that I can do SET NEW.a = 'SYSTEM';

You can try
IF NEW.b IS NULL THEN
SELECT COLUMN_DEFAULT INTO #def FROM information_schema.COLUMNS
WHERE table_schema = 'database_name'
AND table_name = 't_default'
AND column_name = 'a';
SET NEW.a = #def;
END IF;

Related

update a table after inserting a value in the same table using triggers [duplicate]

I am running a MySQL Query. But when a new row is added from form input I get this error:
Error: Can't update table 'brandnames' in stored function/trigger because it is
already used by statement which invoked this stored function/trigger.
From the code:
CREATE TRIGGER `capital` AFTER INSERT ON `brandnames`
FOR EACH
ROW UPDATE brandnames
SET bname = CONCAT( UCASE( LEFT( bname, 1 ) ) , LCASE( SUBSTRING( bname, 2 ) ) )
What does this error mean?
You cannot change a table while the INSERT trigger is firing. The INSERT might do some locking which could result in a deadlock. Also, updating the table from a trigger would then cause the same trigger to fire again in an infinite recursive loop. Both of these reasons are why MySQL prevents you from doing this.
However, depending on what you're trying to achieve, you can access the new values by using NEW.fieldname or even the old values --if doing an UPDATE-- with OLD.
If you had a row named full_brand_name and you wanted to use the first two letters as a short name in the field small_name you could use:
CREATE TRIGGER `capital` BEFORE INSERT ON `brandnames`
FOR EACH ROW BEGIN
SET NEW.short_name = CONCAT(UCASE(LEFT(NEW.full_name,1)) , LCASE(SUBSTRING(NEW.full_name,2)))
END
The correct syntax is:
FOR EACH ROW SET NEW.bname = CONCAT( UCASE( LEFT( NEW.bname, 1 ) )
, LCASE( SUBSTRING( NEW.bname, 2 ) ) )
A "BEFORE-INSERT"-trigger is the only way to realize same-table updates on an insert, and is only possible from MySQL 5.5+. However, the value of an auto-increment field is only available to an "AFTER-INSERT" trigger - it defaults to 0 in the BEFORE-case. Therefore the following example code which would set a previously-calculated surrogate key value based on the auto-increment value id will compile, but not actually work since NEW.id will always be 0:
create table products(id int not null auto_increment, surrogatekey varchar(10), description text);
create trigger trgProductSurrogatekey before insert on product
for each row set NEW.surrogatekey =
(select surrogatekey from surrogatekeys where id = NEW.id);
#gerrit_hoekstra wrote: "However, the value of an auto-increment field is only available to an "AFTER-INSERT" trigger - it defaults to 0 in the BEFORE-case."
That is correct but you can select the auto-increment field value that will be inserted by the subsequent INSERT quite easily. This is an example that works:
CREATE DEFINER = CURRENT_USER TRIGGER `lgffin`.`variable_BEFORE_INSERT` BEFORE INSERT
ON `variable` FOR EACH ROW
BEGIN
SET NEW.prefixed_id = CONCAT(NEW.fixed_variable, (SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'lgffin'
AND TABLE_NAME = 'variable'));
END
I have the same problem and fix by add "new." before the field is updated. And I post full trigger here for someone to want to write a trigger
DELIMITER $$
USE `nc`$$
CREATE
TRIGGER `nhachung_province_count_update` BEFORE UPDATE ON `nhachung`
FOR EACH ROW BEGIN
DECLARE slug_province VARCHAR(128);
DECLARE slug_district VARCHAR(128);
IF old.status!=new.status THEN /* neu doi status */
IF new.status="Y" THEN
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id;
ELSE
UPDATE province SET `count`=`count`-1 WHERE id = new.district_id;
END IF;
ELSEIF old.province_id!=new.province_id THEN /* neu doi province_id + district_id */
UPDATE province SET `count`=`count`+1 WHERE id = new.province_id; /* province_id */
UPDATE province SET `count`=`count`-1 WHERE id = old.province_id;
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id; /* district_id */
UPDATE province SET `count`=`count`-1 WHERE id = old.district_id;
SET slug_province = ( SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1 );
SET slug_district = ( SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1 );
SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district);
ELSEIF old.district_id!=new.district_id THEN
UPDATE province SET `count`=`count`+1 WHERE id = new.district_id;
UPDATE province SET `count`=`count`-1 WHERE id = old.district_id;
SET slug_province = ( SELECT slug FROM province WHERE id= new.province_id LIMIT 0,1 );
SET slug_district = ( SELECT slug FROM province WHERE id= new.district_id LIMIT 0,1 );
SET new.prov_dist_url=CONCAT(slug_province, "/", slug_district);
END IF;
END;
$$
DELIMITER ;
Hope this help someone

Unable to insert write data conditionaly inside trigger (IF, CONCAT, IFNULL) in MySQL

CREATE TRIGGER TR_Update_Member
AFTER UPDATE ON `member`
FOR EACH ROW
BEGIN
DECLARE changeNote VARCHAR(5000) DEFAULT '';
SET changeNote = IF(OLD.Name != NEW.Name,
CONCAT( changeNote,
'Name(',
IFNULL(OLD.Name, '--'),
'->',
IFNULL(NEW.Name, '--'),
'), '
),
changeNote);
SELECT TRIM(TRAILING ', ' FROM changeNote) INTO changeNote;
INSERT INTO `member_change_log`(`Name`) VALUES(changeNote)
END
The above trigger does not insert any data when the name contains null. Could anyone please what is wrong with my code.
The above trigger does not insert any data when the name contains null. Could anyone please what is wrong with my code.
If NEW.Name is NULL then OLD.Name != NEW.Name is NULL too, and IF() executes alternative variant, i.e. you obtain
SET changeNote = changeNote
Simply swap variants:
SET changeNote = IF( OLD.Name = NEW.Name, changeNote, CONCAT( ... ) );
If both OLD.Name and NEW.Name may be NULL then use null-safe compare operator <=> instead of regular compare =.

How to check NEW value exists in BEFORE UPDATE Trigger Mysql

I have table Demo:
create table Demo (
id int(10) auto_increment primary key,
text varchar(30) default null,
istrue boolean default false
);
I want create a update trigger such that:
When Update Demo set istrue = false where id = 1; (not "set text = ") -> normal update.
When Update Demo set text= 'abc' where id = 1; ("set text = ") -> SET NEW.text := concat(OLD.text,'#', NEW.text);
I have implemented trigger as follows:
DELIMITER $$
CREATE TRIGGER update_text
BEFORE update ON Demo
FOR EACH ROW
BEGIN
IF (exists(SELECT NEW.text)) THEN -- how to check NEW.text exists???
SET NEW.text := concat(OLD.text,'#', NEW.text);
END IF;
END$$
DELIMITER ;
But it isn't working! Please help. Thank You!!! (My English is not good. Hope everyone sympathized)
CREATE TRIGGER update_text
BEFORE update
ON Demo
FOR EACH ROW
SET NEW.text = CASE WHEN OLD.text <=> NEW.text
THEN NEW.text
ELSE CONCAT(OLD.text, '#', NEW.text)
END;
PS. Single-statement trigger - BEGIN-END and DELIMITER reassing not needed.
After the deep investigation I have found the way to detect that the field value was set in UPDATE statement.
However, I can't guarantee its reliability. I only check does the substring '`text`' is present in current query text - but there is a lot of situations when this check will give errorneous result, for example, wrong TRUE if this substring is a part of new value, or wrong FALSE if the fieldname is not wrapped with backticks. So be aware.
CREATE TRIGGER update_text
BEFORE update
ON demo
FOR EACH ROW
SET NEW.`text` = CASE WHEN LOCATE('`text`', ( SELECT info
FROM information_schema.processlist
WHERE id = CONNECTION_ID()
)
)
THEN CONCAT(OLD.`text`, '#', NEW.`text`)
ELSE NEW.`text`
END;
fiddle

MySQL - Update a column after information get's inserted

I have a table in MySql table like the following
row_timestamp timestamp
, row_id int(11) auto_increment
, mrn char(17)
, patients_last_name varchar(50)
, patients_first_name varchar(50)
, ssn char(4) default '0000'
, visit_key NULL
upon the insertion of a record, I'd like visit_key to bet set to visit_key = concat(mrn, row_id) I was trying to accomplish this with a before insert trigger to no avail, I kept getting that the mrn column was not in the field select list.
Update
I tried the following, which seems not to work because the auto_increment has not yet incremented:
set new.visit_key = concat(new.mrn, new.row_id)
I also tried
set new.visit_key = concat(new.mrn, max(row_id)+1)
I am thinking of the trigger to sort of act like a calculated field in MS Access, is this reasonable? Thoughts? Would it not be possible to do since the visit_key would technically be NULL and you cannot update a new value?
UPDATE
I used the following code that I adapted from this question here
DELIMITER //
CREATE TRIGGER vkt AFTER INSERT ON demographic_information
FOR EACH ROW
BEGIN
UPDATE `demographic_information` SET visit_key_test = concat(new.mrn, mew.row_id) WHERE row_id = NEW.row_id;
END;
//
DELIMITER ;
and got the following error message:
INSERT INTO `manchuco_nys_trauma`.`demographic_information` (
`row_timestamp` ,
`row_id` ,
`mrn` ,
`patients_last_name` ,
`patients_first_name` ,
`ssn` ,
`visit_id` ,
`visit_key_test`
)
VALUES (
CURRENT_TIMESTAMP , NULL , '123456', 'Sanderson', 'Steven', '1234', '12345670', NULL
)
MySQL said: Documentation
#1442 - Can't update table 'demographic_information' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Thank you,
What you observe seems normal: since you're using BEFORE INSERT the id value doen't exist yet.
And the same applies for your try with concat(new.mrn, **new**.row_id): NEW has no sense at the moment.
So I suggest you use AFTER INSERT instead.
Try selecting the auto increment value inside the trigger:
CREATE TRIGGER trigger_name AFTER INSERT ON yourTable FOR EACH ROW
BEGIN
DECLARE next_id integer;
SET next_id = (SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA='yourDB' AND TABLE_NAME='yourTable');
SET new.visit_key = CONCAT(new.mrn, next_id);
END
I discovered this approach in this SO article.

How to make MySQL produce an error if value not specified on NOT NULL Columns?

Let's assume that I have a NOT NULL column in a table,
How can I make MySQL to produce an error if such statement is used?
INSERT INTO tableName () VALUES ();
Thank you.
To set a column to not null use this syntax :
ALTER TABLE table_name
MODIFY column_name [data type] NOT NULL;
If you column is declared not null an error will be produced !!
If you want a customized error msg then you need to create trigger action !
Here is a trigger that can help you :
DELIMITER $$
CREATE TRIGGER trgBEFORE UPDATE ON `tbl`
FOR EACH ROW BEGIN
declare msg varchar(255);
IF (NEW.col1IS NULL ) THEN
set msg = concat('MyTriggerError: Trying to insert a null value );
signal sqlstate '45000' set message_text = msg;
ELSE
SET NEW.col1= NEW.col1);
END IF;
END$$
DELIMITER ;
I know this is late but it might help someone.
You can set the SQL mode, either in the configuration file or at runtime for current session.
To produce the error you need to enable strict sql mode with:
SET GLOBAL sql_mode = 'STRICT_ALL_TABLES'; or SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';
Here is a link for more information on sql modes.
How to make MySQL produce an error, when inserting a row to a table containing NOT NULL column, when not specifying a value to that column like in "INSERT INTO tableName () VALUES()".
Is there a way without a trigger?
This is possible without a trigger only when you define no default when defining a column. Also the same is applicable for alter ... column ...
Example 1:
create table ck_nn( i int not null );
insert into ck_nn values();
The above insert throws an error as no default is defined on the column.
Message can be something like Field 'i' doesn't have a default value.
Example 2:
create table ck_nn2( i2 int not null default 999 );
insert into ck_nn2 values();
The above insert won't throw any error as default value is defined on the column.
select * from ck_nn2;
+-----+
| i2 |
+-----+
| 999 |
+-----+
Example # SQL Fiddle