Before insert trigger prevents following INSERT INTO statements to execute - mysql

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 ;

Related

Constrain grandchild table by grandparent key through parent [MySQL] [duplicate]

I would like to add a constraint that will check values from related table.
I have 3 tables:
CREATE TABLE somethink_usr_rel (
user_id BIGINT NOT NULL,
stomethink_id BIGINT NOT NULL
);
CREATE TABLE usr (
id BIGINT NOT NULL,
role_id BIGINT NOT NULL
);
CREATE TABLE role (
id BIGINT NOT NULL,
type BIGINT NOT NULL
);
(If you want me to put constraint with FK let me know.)
I want to add a constraint to somethink_usr_rel that checks type in role ("two tables away"), e.g.:
ALTER TABLE somethink_usr_rel
ADD CONSTRAINT CH_sm_usr_type_check
CHECK (usr.role.type = 'SOME_ENUM');
I tried to do this with JOINs but didn't succeed. Any idea how to achieve it?
CHECK constraints cannot currently reference other tables. The manual:
Currently, CHECK expressions cannot contain subqueries nor refer to
variables other than columns of the current row.
One way is to use a trigger like demonstrated by #Wolph.
A clean solution without triggers: add redundant columns and include them in FOREIGN KEY constraints, which are the first choice to enforce referential integrity. Related answer on dba.SE with detailed instructions:
Enforcing constraints “two tables away”
Another option would be to "fake" an IMMUTABLE function doing the check and use that in a CHECK constraint. Postgres will allow this, but be aware of possible caveats. Best make that a NOT VALID constraint. See:
Disable all constraints and table checks while restoring a dump
A CHECK constraint is not an option if you need joins. You can create a trigger which raises an error instead.
Have a look at this example: http://www.postgresql.org/docs/9.1/static/plpgsql-trigger.html#PLPGSQL-TRIGGER-EXAMPLE
CREATE TABLE emp (
empname text,
salary integer,
last_date timestamp,
last_user text
);
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
END IF;
-- Remember who changed the payroll when
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
...i did it so (nazwa=user name, firma = company name) :
CREATE TABLE users
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
nazwa character varying(20),
firma character varying(50)
);
CREATE TABLE test
(
id bigserial CONSTRAINT firstkey PRIMARY KEY,
firma character varying(50),
towar character varying(20),
nazwisko character varying(20)
);
ALTER TABLE public.test ENABLE ROW LEVEL SECURITY;
CREATE OR REPLACE FUNCTION whoIAM3() RETURNS varchar(50) as $$
declare
result varchar(50);
BEGIN
select into result users.firma from users where users.nazwa = current_user;
return result;
END;
$$ LANGUAGE plpgsql;
CREATE POLICY user_policy ON public.test
USING (firma = whoIAM3());
CREATE FUNCTION test_trigger_function()
RETURNS trigger AS $$
BEGIN
NEW.firma:=whoIam3();
return NEW;
END
$$ LANGUAGE 'plpgsql'
CREATE TRIGGER test_trigger_insert BEFORE INSERT ON test FOR EACH ROW EXECUTE PROCEDURE test_trigger_function();

Trying to insert multiple rows via a trigger (on insert) is causing errors

Trying to use a trigger to insert multiple rows in a table (on insert) but it's only working with one row. I get an error return from the form (nothing specific, just that there was an error with the original insert)
Works fine with 1 row, but multiple crashes. What's wrong with this syntax?
BEGIN
set #moonid = 1;
insert into quicknotedesc (custid,moonid) VALUES (New.id,(#moonid)),(New.id,(#moonid+1));
END
The syntax of the trigger body appears to be valid.
With almost every SQL client, there is a mechanism to detect an error condition and to retrieve the error message. Maybe the error is because of an attempt to violate a unique constraint on the custid column of quicknotedesc, or some other constraint violation. We're just guessing.
Consider enabling the client to retrieve the actual error message. And consider testing the behavior of the trigger from another client, like the MySQL command line client.
Again, to answer the question that was asked:
The syntax of the trigger body appears to be valid.
Demonstration:
CREATE TABLE quicknotedesc
( custid BIGINT UNSIGNED NOT NULL
, moonid BIGINT UNSIGNED NOT NULL
, PRIMARY KEY (custid, moonid)
);
CREATE TABLE foo
( id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT
);
DELIMITER $$
CREATE TRIGGER foo_ai
AFTER INSERT ON foo
FOR EACH ROW
BEGIN
SET #moonid = 1;
INSERT INTO quicknotedesc (custid,moonid) VALUES (New.id,(#moonid)),(New.id,(#moonid+1));
END$$
DELIMITER ;
INSERT INTO foo (id) VALUES (NULL) ;
1 row(s) affected
SELECT * FROM quicknotedesc ;
custid moonid
------ ------
1 1
1 2

How can I update MySQL table row's when 'BEFORE UPDATE' trigger is firing?

I created a table
Databases Name - mytrigger;
Table name - employee_audit
use mytrigger;
create table employee_audit(
id int auto_increment primary key,
employeeNumber int not null,
lastName varchar(50) not null,
changee datetime default null,
action varchar(50) default null
);
After that, I created one update trigger
My trigger name is
before_employees_update
DELIMITER $$
create trigger before_employees_update
before update on employee_audit
for each row
begin
insert into employee_audit
set action ='update',
employeeNumber = OLD.employeeNumber,
lastName = OLD.lastName,
changee = now();
end$$
DELIMITER ;
After that, I inserted values in table using this command ->
insert into employee_audit values(1,112,'prakash','2015-11-12 15:36:20' ,' ');
After that, I want to update my table row where id =1
update employee_audit set lastName = 'Sharma' where employeeNumber =112;
But it is not executed give an error
ERROR 1442 (HY000): Can't update table 'employee_audit' in stored
function/trigger because it is already used by statement which invoked
this stored function/trigger.
When I searched on Google I found a lot of Question with the same error. But not able to fix my problem. what is the reason I'm not able to update my row?
What i suggest,you can create one log table like employee_audit_LOG .
And on every insert or update in main table you can make new entry in this table or update existing record.
Also you can add updated_timestamp column to that LOG table which maintain when did specific record get updated.
The error itself tells you the answer. This is because, you can't use the same table on which trigger is being executed. You need to store your audit logs into some different table.

How to make ALPHANUMERIC constraint in mysql?

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;

MySQL Insert/Update Trigger with AUTO_INCREMENT

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.