MySQL, trigger that generates primary key before insert a row - mysql

I'm trying to generate a primary key based on current date and time,
Here's my trigger:
DELIMITER $$
CREATE TRIGGER cuenta
BEFORE UPDATE ON cuenta
FOR EACH ROW
BEGIN
INSERT INTO cuenta VALUES (NULL);
SET NEW.NoCuenta = DATE_FORMAT(NOW(), '%000%d%m%y%h%i%s');
END$$
DELIMITER ;
My table cuenta:
NoCuenta, varchar(15), NOT NULL.
TipoCuenta, varchar(7),
saldo, float
IDCliente, int(8).
Then I try to insert:
insert into banco.cuenta(TipoCuenta, saldo, IDCliente)
VALUES('Debito','12500.5','1');
The result:
1 row(s) affected, 1 warning(s): 1364 Field 'NoCuenta' doesn't have a default value
But when I type select*from cuenta... NoCuenta field is empty.
And then when I try to insert a new row, it shows this:
Error Code: 1062. Duplicate entry '' for key 'PRIMARY'
Please HELP!!

Why are you inserting into the table in the trigger? Just try this:
DELIMITER $$
CREATE TRIGGER cuenta
BEFORE UPDATE ON cuenta
FOR EACH ROW
BEGIN
SET NEW.NoCuenta = DATE_FORMAT(NOW(), '%000%d%m%y%h%i%s');
END$$
DELIMITER ;

Related

Create trigger before insert

I want to create a trigger in Mysql.
Before Insert and before Update , to only insert the values if the ID is present in another table.
Here is my trigger (before insert) which does not work:
DELIMITER $$
CREATE TRIGGER
`before_insert_id`
BEFORE INSERT ON
`table2`
FOR EACH ROW
BEGIN
DECLARE msg VARCHAR(255);
IF NEW.id =
( SELECT id
FROM table2
WHERE NEW.id not in (select id from table1)
)
THEN
SET msg = 'id not in table1';
SIGNAL SQLSTATE '45002' SET message_text = msg ;
END IF ;
END ;
$$
DELIMITER ;
Also should we insert values in table2 inside after if statement passes?or is it just for checking only?
IF NOT EXISTS (select * from table1 where id = new.id) then set msg = 'id not in table1' signal... end if; If it exists then data gets inserted automatically.
... only insert the values if the ID is present in another table.
This sound like you just need a foreign key constraint, not a trigger.
ALTER TABLE table2 ADD FOREIGN KEY (id) REFERENCES table1(id);
That will throw an error if you try to insert a row with an id that is not present in table1.
No trigger required.

Trigger in MySQL "BEFORE DELETE"

Deleting a record gives me below error:
ERROR 1442: 1442: Can't update table 'categoria' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
This is my trigger:
DROP trigger IF EXISTS tg_eliminarCategoria;
DELIMITER $$
CREATE TRIGGER tg_eliminarCategoria
BEFORE DELETE ON Categoria
FOR EACH ROW
BEGIN
IF NOT EXISTS (SELECT * FROM Categoria WHERE nombreCategoria = 'Sin Categoria') THEN
INSERT INTO Categoria (nombreCategoria) VALUES ('Sin Categoria');
END IF;
SET #idCategoria = (SELECT idCategoria FROM Categoria WHERE nombreCategoria = 'Sin Categoria');
UPDATE Contacto SET idCategoria=#idCategoria WHERE idCategoria=OLD.idCategoria;
END$$
DELIMITER ;
The trigger is that by deleting a record from the "Categoria" table, it checks if there is a "Sin Categoria" record and if it does not exist, it modifies all records in the "Contacto" table containing the record deleted by The new record.
Sorry for my English, I'm still learning.
I guess that you want to make sure there is at least one row in the table for 'Sin Categoria'.
Another way to do this is to raise a SIGNAL (like an exception) if someone tries to delete 'Sin Categoria'.
mysql> DROP trigger IF EXISTS tg_eliminarCategoria;
mysql> DELIMITER $$
mysql> CREATE TRIGGER tg_eliminarCategoria
BEFORE DELETE ON Categoria
FOR EACH ROW
BEGIN
IF OLD.nombreCategoria = 'Sin Categoria' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'No debe eliminar la categoría especial: Sin Categoria';
END IF;
END$$
mysql> DELIMITER ;
mysql> delete from Categoria;
ERROR 1644 (45000): No debe eliminar la categoría especial: Sin Categoria
However, I think I have a better recommendation. I am guessing you use this for foreign keys that must reference a category, like this:
CREATE TABLE Contacto (
idContacto INT AUTO_INCREMENT PRIMARY KEY,
idCategoria INT NOT NULL,
FOREIGN KEY (idCategoria) REFERENCES Categoria(idCategoria)
);
When a Contacto has no Categoria, you reference the 'Sin Categoria' row. And you want to make sure no one deletes that row in the Categoria table.
Instead, I recommend using NULL when a row in Contacto has no Categoria. Just make Contacto.idCategoria allow NULL:
CREATE TABLE Contacto (
idContacto INT AUTO_INCREMENT PRIMARY KEY,
idCategoria INT DEFAULT NULL,
FOREIGN KEY (idCategoria) REFERENCES Categoria(idCategoria)
);
INSERT INTO Contacto
SET idContacto = 1234,
idCategoria = NULL;
Then you don't need any row in Categoria named "Sin Categoria".

Creating a BEFORE INSERT TRIGGER IN MYSQL

I need help creating a BEFORE INSERT TRIGGER on mySQL Bench. im new to this please.
CREATE TABLE `quincyninying`.`toytracking` (
`Toyid` INT NOT NULL,
`ToyName` VARCHAR(50) NULL,
`Toycost` DECIMAL NULL,
`ToyAction` VARCHAR(50) NULL,
`ActionDate` DATETIME NULL,
PRIMARY KEY (`Toyid`));
CREATE TABLE `quincyninying`.`toy` (
`Toyid` INT NOT NULL,
`ToyName` VARCHAR(50) NULL,
`Toycost` DECIMAL NULL,
PRIMARY KEY (`Toyid`));
Create a BEFORE INSERT trigger on the toy table that adds a record to the toytracking table with the information from the toy table record that is being INSERTED, hard coded ToyAction that will be ‘INSERT’ and the current Date and time the record is inserted.
ERROR 1054: Unknown column 'inserted' in 'NEW' SQL Statement:
CREATE DEFINER = CURRENT_USER TRIGGER `quincyninying`.`toy_BEFORE_INSERT` BEFORE INSERT ON `toy`
FOR EACH ROW
BEGIN
IF new.inserted THEN
SET #toyaction = 'DELETE';
ELSE
SET #toyaction = 'NEW';
END IF;
INSERT INTO `quincyninying`.`toytracking` (toyId, ToyName, ToyCost, Toyaction, ActionDate)
VALUES (new.toyid, new.Toyname, new.Toycost,#Toyaction, now());
END
It throws me an error saying " ERROR 1054: Unknown column 'inserted' in 'NEW' "
Get rid of the IF new.inserted test, since there's no column with that name, and just hard-code INSERT as the value for the ToyAction column as you stated in the requirements.
CREATE DEFINER = CURRENT_USER TRIGGER `quincyninying`.`toy_BEFORE_INSERT` BEFORE INSERT ON `toy`
FOR EACH ROW
BEGIN
INSERT INTO `quincyninying`.`toytracking` (toyId, ToyName, ToyCost, Toyaction, ActionDate)
VALUES (new.toyid, new.Toyname, new.Toycost, 'INSERT', now());
END
Try this:
DELIMITER $$
CREATE
TRIGGER toy_before_insert BEFORE INSERT
ON toy
FOR EACH ROW BEGIN
IF NEW.Toyaction THEN
SET #Toyaction = 'DELETE';
ELSE
SET #Toyaction = 'NEW';
END IF;
INSERT INTO toytracking (toyId, ToyName, ToyCost, Toyaction, ActionDate) VALUES (NEW.Toyid, NEW.ToyName, NEW.ToyCost, #Toyaction, NOW());
END$$
DELIMITER ;

How to get id after insert statement in MySQL

I have such procedure
DROP PROCEDURE IF EXISTS CreateNativeUser;
delimiter $$
CREATE PROCEDURE CreateNativeUser (p_email varchar(100), p_pass varchar(32))
BEGIN
insert into users(email) values (p_email);
insert into user_logins_native() values(???, p_email, p_pass);
commit;
END $$
delimiter ;
and I need some way to get user_id because user_logins_native has a foreign key on user_id column of users table
Using the LAST_INSERT_ID() function:
insert into users(email) values (p_email);
insert into user_logins_native() values(LAST_INSERT_ID(), p_email, p_pass);

MySQL: Custom row validation

I have such example:
CREATE TABLE a(
id INT PRIMARY KEY AUTO_INCREMENT,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES a(id)
);
DELIMITER ;;
CREATE TRIGGER a_insert BEFORE INSERT ON a
FOR EACH ROW
BEGIN
SIGNAL SQLSTATE '01431' SET MESSAGE_TEXT = 'The foreign data source you are trying to reference does not exist.';
END;;
DELIMITER ;
INSERT INTO a(parent_id) VALUES (NULL);
INSERT INTO a(parent_id) VALUES (1);
INSERT INTO a(parent_id) VALUES (2);
INSERT INTO a(parent_id) VALUES (4);
INSERT INTO a(parent_id) VALUES (999);
SELECT * FROM a
This end up with 4 recods:
----------------
id parent_id
----------------
1 NULL
2 1
3 2
4 4
I found post online that MySQL does not support rollbacks in triggers. That is a problem because I want such hierarchy where no row points to it self and inserts like the one with ID=4 works just fine. How do I ensure there are no such records in database?
Well, the problem is with auto_increment, because you in BEFORE INSERT event you don't have that value assigned yet. On the other hand in AFTER INSERT event you can't do anything with it.
If you want to use auto_increment id column a possible solution is to use separate table for sequencing.
Your schema would look like
CREATE TABLE a_seq(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE a(
id INT NOT NULL PRIMARY KEY DEFAULT 0,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES a(id)
);
And your trigger
DELIMITER $$
CREATE TRIGGER a_insert
BEFORE INSERT ON a
FOR EACH ROW
BEGIN
INSERT INTO a_seq VALUES(NULL);
SET NEW.id = LAST_INSERT_ID();
IF NEW.id = NEW.parent_id THEN
SET NEW.id = NULL;
END IF;
END$$
DELIMITER ;
If id=parent_id the trigger deliberately violates NOT NULL constraint assigning NULL value. Therefore this record won't be inserted.
Here is SQLFiddle demo. Uncomment last insert statement. It won't allow you to make such insert.