Hi to all im trying to create a trigger for this table:
create table Episode(
title varchar(25) not null,
number int not null,
length time not null,
aired date not null,
serie_name varchar(25),
PRIMARY KEY(title,number),
FOREIGN KEY (serie_name)REFERENCES Serie(name)
) ENGINE=InnoDB;
this is a table of a db that saves some tv series...so the trigger have to check if i m trying to insert a new episode that had benn aired before the precedent one....But i have some problem any solutions?
i tried this:
create trigger ControlDataEp
before insert on Episode
for each row
begin
if new.aired<(select aired from Episode where title=new.title and number=new.number-1)
then raise.application_error(-21,'error');
end if;
end;
If you don't that much care about returning meaningful error message you can simplify your trigger to one statement
CREATE TRIGGER ControlDataEp
BEFORE INSERT ON Episode
FOR EACH ROW
SET NEW.aired =
(
SELECT IF(IFNULL(MAX(aired), 0) < NEW.aired, NEW.aired, NULL)
FROM Episode
WHERE title = NEW.title
AND number = NEW.number - 1
);
What it does it violates NOT NULL constraint on aired column.
Here is SQLFiddle demo. Uncomment last insert statement
Now if you do need to return a custom error message:
You can use SIGNAL but only if you on MySql 5.5 and higher
Use one the hackish ways (read e.g. TRIGGERs that cause INSERTs to fail? Possible?, Throw an error in a MySQL trigger)
If I were you, I wouldn't use a trigger when there's no need to.
You can use
INSERT IGNORE ...
INSERT ... ON DUPLICATE KEY UPDATE ...
REPLACE ...
Please have a look in the respective manual pages I linked for additional information.
To explain, why your solution doesn't work:
if new.aired<(select aired
Your subquery might return multiple rows. Use SELECT MAX(aired) ... instead.
... and number=new.number-1)
It's a bad idea to rely on code outside the database to make sure, that data in the database is okay.
then raise.application_error(-21,'error');
raise.application_error() is not a MySQL built-in function. You can't call functions from your code in MySQL like this. If you really want to raise an error in MySQL use SIGNALs
Related
I have a SQL table that can reference another record in the table as its parent but should not reference itself. I have attempted to enforce this with a CHECK constraint but my attempts have failed as the id is an auto-increment column. Is there any other way to ensure that parent_id <> id?
My current attempt, which fails with error Check constraint 'not_own_parent' cannot refer to an auto-increment column. (errno 3818):
CREATE TABLE `content` (
`id` serial PRIMARY KEY NOT NULL,
`item_id` int NOT NULL,
`nested_item_id` int,
`block_id` int,
`order` int NOT NULL,
CONSTRAINT not_own_parent CHECK (nested_item_id <> id)
);
Here's a demo of using a trigger to cancel an insert that violates the condition you describe. You must use an AFTER trigger because in a BEFORE trigger the auto-increment value has not yet been generated.
mysql> delimiter ;;
mysql> create trigger t after insert on content
-> for each row begin
-> if NEW.nested_item_id = NEW.id then
-> signal sqlstate '45000' set message_text = 'content cannot reference itself';
-> end if;
-> end;;
mysql> delimiter ;
mysql> insert into content set item_id = 1, nested_item_id = 1, `order` = 1;
ERROR 1644 (45000): content cannot reference itself
mysql> insert into content set item_id = 1, nested_item_id = 2, `order` = 1;
Query OK, 1 row affected (0.01 sec)
Don't put this kind of thing in a constraint. For one thing, you can't do it directly in MySql. You'd have to use a trigger or something.
Instead:
write your CRUD code carefully, so it avoids generating incorrect rows. You have to do that anyway.
write a little program called "database_consistent" or something. Have it run a bunch of queries looking for any errors like the one you're trying to avoid. Have it send emails or SMSs if it finds problems. Run it often during development and at least daily in production.
One way to control auto-generated live values is by using triggers to manage new values.
For example, create instead of insert trigger to control newly generated ID. In triggers, you can make decisions based on the new value.
For an mysql v8.0.18 project with mariaDb 10.4.10
I would like add to my existing table an unique constraint for multi columns
ALTER TABLE 'new_purchasseorder' ADD UNIQUE ('created', 'fk_customer_id', 'fk_removal_id', 'fk_recipient_id')
but would like no check for old datas
something like that:
where id > 3869
i also tried the SET FOREIGN_KEY_CHECKS=0; but nor working in this case.
is it possible ?
My table looks like:
You can't do this with a unique constraint as far as I know, because, as you have already discovered, such a constraint will be applied to the entire table, regardless of id value. One workaround might be to use a before insert trigger, which does the assertion:
DELIMITER //
CREATE TRIGGER contacts_before_insert
BEFORE INSERT ON new_purchasseorder FOR EACH ROW
BEGIN
IF EXISTS (SELECT 1 FROM new_purchasseorder
WHERE created = NEW.created AND
fk_customer_id = NEW.fk_customer_id AND
fk_removal_id = NEW.fk_removal_id AND
fk_recipient_id = NEW.fk_recipient_id)
THEN
signal sqlstate '45000';
END IF;
END; //
DELIMITER ;
This insert trigger would cause any insert incoming with what your unique index defines as duplicate data to fail with an error, effectively blocking that insert.
A better long term (and easier) strategy might be to just fix your old data so that it can pass the requirements of the unique constraint.
Starting version 8.0.13, MySQL supports functional key parts - basically indexes on expression. Assuming that all 4 columns are non-nullable, you can do:
create unique index idx_new_purchaseorder on new_purchaseorder (
(
case when id > 3869
then concat_ws('$$', created, fk_customer_id, fk_removal_id, fk_recipient_id)
end
)
)
The case expression filters on id values, and generates a concatenated string that should be unique for rows that comply to the filter. I used some fancy characters to avoid "fake" duplicates.
Demo on DB Fiddle
Hi I want to create trigger if it's condition satisfy then it's body should be executed and I want to display some message or any data that should be displayed if trigger body executed.
I want that if quantity of product went less then 50 then it should display message or some data.
Is it possible to display message ?
Here testdata is table name.
Code :
delimiter //
create trigger trigger2 before update on test.testdata
for each row
begin
if new.qty < 50 then
**display here some message that quantity is less**
end if;
end;
//
delimiter ;
You cannot do it, there is no place to output them in MySQL. As a work around you can add your message to the table, and then read this table.
Short example -
CREATE TABLE table1 (
column1 VARCHAR(255) DEFAULT NULL
);
CREATE TABLE messages (
id INT(11) NOT NULL AUTO_INCREMENT,
message VARCHAR(255) DEFAULT NULL,
time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DELIMITER $$
CREATE TRIGGER trigger1
AFTER INSERT
ON table1
FOR EACH ROW
BEGIN
INSERT INTO messages(message) VALUES ('new action');
END
$$
DELIMITER ;
Also, you could use UDF function write your logic.
More information - CREATE FUNCTION Syntax for User-Defined Functions.
For Quick and plain answering: You cannot Display Messages From Triggers. You may Only Throw errors.
You are propably not knowing the reason u use triggers in databases assuming from your question. We all have passed that level so dont worry. U have understood the syntax when we use triggers but not how and what they can do and not.
A trigger will do (for your case BEFORE an UPDATE) something concerning the database and only that.
That means the trigger cannot display any message on your screen. You can only handle database staff and not all of the actions are allowed for that too or some actions arent even recommended!.
That is for the theory part.
To give you a solution to your problem now.
The only thing you can do to know when the trigger has worked (that means when the new.qua<50) or basically check anything with any other trigger is the following. (Just a small fast solution):
You need to create a Table that will handle all logging of the
triggers.
Add in it an ID field, a descr field that will hold the action of
the triggerex. BefUpdate, BefInsert etc. another field for the
propably the condition that triggered the logging and antyhing else
u want displayed later in the application.
Then inside the if condition u are using write and insert
statemement to fill the info in the new (logging) table.
in your app later select that logging table to see the messages.
That is a useful and fast way to log, not only triggers but also functions (stored procs).
Judt for reference i give you s sample code with the CREATE, and the INSERT statement for your trigger.
CREATE TABLE LOGGER (
ID BIGINT PRIMARY KEY AUTO_INCREMENT,
DESCR_ACTIVITY VARCHAR(10),
ACTIVITY VARCHAR(50),
DT TIMESTAMP,
CONDITIONVALUE VARCHAR(50)
)
In the IF of your code now make it as :
if new.qty < 50 then
INSERT INTO LOGGER VALUES ('BEFINS','CHECKING QUA',NULL,'QUANTITY IS LOWER THAN 50')
end if;
And even from the workbench or from your application u can just :
SELECT * FROM LOGGER
to see the loggings.
But if i am confused from the reading and you want just to throw an error u can read the Mysql Documentation concerning throwing errors:
enter link description here
What u can do is in your if condition write something like:
if new.qty < 50 then
SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT = 'Lower than 50', MYSQL_ERRNO = 1000;
endif;
What u should always NOT DO is alter the same table that a trigger is assigned and use only small portion of not so complex code in the trigger.
Hope i helped a bit.
Also, you can display any message using the select command.
IF (NEW.qty < 50) THEN
SELECT "message that quantity is less" AS Output;
END IF
Place above code inside the trigger. It will print the output
Suppose I have an attribute called phone number and I would like to enforce certain validity on the entries to this field. Can I use regular expression for this purpose, since Regular Expression is very flexible at defining constraints.
Yes, you can. MySQL supports regex (http://dev.mysql.com/doc/refman/5.6/en/regexp.html) and for data validation you should use a trigger since MySQL doesn't support CHECK constraint (you can always move to PostgreSQL as an alternative:). NB! Be aware that even though MySQL does have CHECK constraint construct, unfortunately MySQL (so far 5.6) does not validate data against check constraints. According to http://dev.mysql.com/doc/refman/5.6/en/create-table.html: "The CHECK clause is parsed but ignored by all storage engines."
You can add a check constraint for a column phone:
CREATE TABLE data (
phone varchar(100)
);
DELIMITER $$
CREATE TRIGGER trig_phone_check BEFORE INSERT ON data
FOR EACH ROW
BEGIN
IF (NEW.phone REGEXP '^(\\+?[0-9]{1,4}-)?[0-9]{3,10}$' ) = 0 THEN
SIGNAL SQLSTATE '12345'
SET MESSAGE_TEXT = 'Wroooong!!!';
END IF;
END$$
DELIMITER ;
INSERT INTO data VALUES ('+64-221221442'); -- should be OK
INSERT INTO data VALUES ('+64-22122 WRONG 1442'); -- will fail with the error: #1644 - Wroooong!!!
However you should not rely merely on MySQL (data layer in your case) for data validation. The data should be validated on all levels of your app.
MySQL 8.0.16 (2019-04-25) and MariaDB 10.2.1 (2016-04-18) now not only parse CHECK constraint but also enforces it.
MySQL: https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html
MariaDB: https://mariadb.com/kb/en/constraint/
Actually, we can can set regular expression within check constraints in MySQL.
Eg.,:
create table fk
(
empid int not null unique,
age int check(age between 18 and 60),
email varchar(20) default 'N/A',
secondary_email varchar(20) check(secondary_email RLIKE'^[a-zA-Z]#[a-zA-Z0-9]\.[a-z,A-Z]{2,4}'),
deptid int check(deptid in(10,20,30))
)
;
This INSERT query will work:
insert into fk values(1,19,'a#a.com','a#b.com', 30);
This INSERT query will not work:
insert into fk values(2,19,'a#a.com','a#bc.com', 30);
I have to create a table as following
Borrower(customerNo,LoanNo)
customers can take loans if they havent take more than 3 loans.
I created table as follows
create table borrower(
customerno int(5),
LoanNo int(5),
primary key(customerno,loanno),
check( customerno not in
(select customerno from borrower group by customerno having count(loanno)>=4))
);
But it givs me an error saying
[root#localhost:3306] ERROR 1146: Table 'test.borrower' doesn't exist
Can someone tell me how to fix this error??
The reason it's giving the error is because the CHECK constraint refers to the table being created, but it doesn't exist at the time that the statement is parsed.
But I have some bad news for you... mysql ignores CHECK constraints. It is allowed as syntax only for compatibility with create statements from other databases.
See the mysql documentation for CREATE TABLE:
The CHECK clause is parsed but ignored by all storage engines.
You'll have to use a trigger, but note that you can't throw an exception from one. The best you can hope for is when you detect a problem, do something like execute SELECT * FROM TOO_MANY_LOANS and hope that the caller figures out what the error "No such table TOO_MANY_LOANS" really means.
As this belongs to the business rules and not to data structure you should use a Stored Procedure like this
DELIMITER ;;
CREATE PROCEDURE `AddCustomerLoan`(IN Acustomerno int(5), IN ALoanNo int(5), OUT ResultCode INT)
BEGIN
SELECT COUNT(*)
INTO #LoanCount
FROM borrower
WHERE customerno = Acustomerno;
IF #LoanCount < 4 THEN
INSERT INTO borrower ( customerno, LoanNo )
VALUES ( Acustomerno, ALoanNo );
SET ResultCode = 0;
ELSE
-- Too many Entries
SET ResultCode = 1;
END IF;
END;;
DELIMITER ;
The ResultCode will inform your application if it was successful or not, and why not successful.
Another advantage is that you can modify the maximum entries or get the maximum entries per customer, without changing your application code.