Given this table:
CREATE TABLE object
(
object_id int NOT NULL AUTO_INCREMENT,
root_id int NOT NULL,
name varchar(255),
PRIMARY KEY(object_id)
)
The column root_id is a self referential foreign key.
Basically what I want is root_id to default to the same value as object_id when a new record is inserted, if root_id is NULL.
I thought a trigger would solve this.
CREATE TRIGGER add_default_original_id AFTER INSERT ON object
FOR EACH ROW BEGIN
IF (NEW.original_id IS NULL) THEN
SET NEW.original_id = NEW.object_id;
END IF;
END;
So when I run this:
INSERT INTO object(name) values('test')
I want both object_id and original_id to have the same auto-generated value
With trigger AFTER INSERT I get the
Error Code: 1362. Updating of NEW row is not allowed in after trigger
With trigger BEFORE INSERT I run get the
Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (...)
I guess because object_id haven't gotten the generated value yet.
Of course I could just do this "manually" in my code after the insert, but I'm trying to do as few code managed statements as possible. Is there any way to easily achieve this during the insert statement?
You must use two statement:
INSERT INTO object(object_id, root_id, name) values(NULL, NULL, 'test')
UPDATE object set root_id = (select max(object_id) from object)
where id = (select max(object_id) from object)
There is another possible solution although a bit quirk:
CREATE TRIGGER add_default_original_id AFTER INSERT ON object
FOR EACH ROW BEGIN
BEGIN
SET NEW.root_id = (
SELECT `AUTO_INCREMENT`
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'XXX'
AND TABLE_NAME = 'object');
END
Hope this helps.
Related
I have a MySQL table created using the following syntax:
CREATE TABLE `name_to_id` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(128),
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
);
And a common query this table would like to answer is name to id look-up, but if the <name, id> pair does not exist in the DB, then also insert a new entry and return the newly inserted id.
Can I know should I do that in MySQL?
As commented by Strawberry, this cannot be performed in a single query.
However, here is a stored procedure that should do what you expect. First, it uses the INSERT ... ON DUPLICATE KEYS UPDATE syntax to insert new names ; this actually relies on the UNIQUE key that you correctly set up on the name column.
DELIMITER //
CREATE PROCEDURE get_id_by_name(IN p_name VARCHAR(128))
BEGIN
INSERT INTO name_to_id(name) VALUE(p_name) ON DUPLICATE KEY UPDATE name = p_name;
SELECT id FROM name_to_id WHERE name = p_name;
END //
DELIMITER ;
Demo on DB Fiddle.
This approach is efficient, but the downside of ON DUPLICATE KEYS is that it wastes id sequences : everytime the query is called, the sequence is autoincremented (even if a record already exists). This can be seen in the fiddle.
Here is another approach, that won't burn sequence numbers :
DELIMITER //
CREATE PROCEDURE get_id_by_name(IN p_name VARCHAR(128))
BEGIN
DECLARE p_id bigint(20) unsigned;
SELECT id INTO p_id FROM name_to_id WHERE name = p_name;
IF (p_id IS NULL) THEN
INSERT INTO name_to_id(name) VALUE(p_name);
SELECT LAST_INSERT_ID();
ELSE
SELECT p_id;
END IF;
END //
DELIMITER ;
Demo on DB Fiddle.
you can do this on stored proc, if the select statement did not return a result, then you can execute the insert statement
I hope to this work.
When UserAccount table duplicated, Out Parameter put -1.
When UserInfo table duplicated, Out Parameter put -2.
When all work is succeed, Out Parameter put LAST_INSERT_ID.
UserAccount Table
CREATE TABLE UserAccount (
SocialType ENUM('Google', 'Facebook'),
SocialID BINARY(16),
UserID INT UNIQUE NOT NULL AUTO_INCREMENT,
PRIMARY KEY(SocialType, SocialID)
);
UserInfo Table
CREATE TABLE UserInfo (
UserID INT,
Nickname VARCHAR(20) UNIQUE,
PRIMARY KEY(UserID),
FOREIGN KEY(UserID) REFERENCES UserAccount(UserID)
ON DELETE CASCADE,
);
I want to insert tables with duplicate checking in procedure.
But it failed to work and seems inefficient.
DELIMITER $$
CREATE PROCEDURE usp_CreateNewUser(
socialType ENUM('Google','Facebook'),
socialID VARCHAR(100),
nickname VARCHAR(20),
OUT result INT)
Work:BEGIN
IF EXISTS(SELECT 1 FROM UserAccount WHERE SocialType = socialType AND SocialID = UNHEX(MD5(socialID)))
THEN
SET result = -1;
Leave Work;
END IF;
IF EXISTS(SELECT 1 FROM UserInfo WHERE Nickname = nickname)
THEN
SET result = -2;
Leave Work;
END IF;
INSERT INTO UserAccount() VALUE(socialType, UNHEX(MD5(socialID)), 0);
INSERT INTO UserInfo(UserID, Nickname) VALUE(LAST_INSERT_ID(), nickname);
SET result = LAST_INSERT_ID();
END $$
DELIMITER ;
What is the best way I can do in this situation?
Thanks.
Judging from your trigger, you don't want to have duplicate keys in your database, as you are bypassing the insert when you find one.
So all you have to do is have your unique indexes set up correctly in your first table, which will do that work for you, and produce a display in your application.
Do the below:
ALTER TABLE `UserAccount` ADD UNIQUE `UserAccount`(`socialType`, `socialID`);
Since your data appears to be 1 to 1, id put all of this in the same table, and then you wouldn't need the trigger.
I need a solution for copy the auto increment value to userid column when insert the record.
I have two column like id(AI),userid. Here I have used a trigger
CREATE TRIGGER adduserid BEFORE INSERT ON user
FOR EACH ROW SET NEW.userid = NEW.id
The problems is triggers invoke before insert,so it will get id as 0.
Suggest me how can I modify the trigger?
Sample:
Table definition:
CREATE TABLE departments (
ID NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
CREATE SEQUENCE dept_seq;
Trigger definition:
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON departments
FOR EACH ROW
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;
Syntax Link1:https://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
Let's say I have two tables:
info(id PRIMARY KEY, opendate NOT NULL, closedate)
fileinfo(fileno PRIMARY KEY, id FOREIGN KEY REFERENCES info.id)
I would like to allow new entries into fileinfo only if the corresponding value of info.closedate is null. Is there a way to do that?
You can attach a trigger to the fileinfo table, to run on INSERT, which looks up the closedate on info, and throws an error if it's not null.
EDIT: Added example of a SQLServer trigger which would do the same thing. Edit as MySQL syntax requires.
CREATE TRIGGER InsertFileInfo
ON fileinfo
AFTER INSERT
AS
BEGIN
declare #closedate DateTime ;
select #closedate = closedate from info where id in (select id from new);
if #closedate is not null
begin
raiserror ('CloseDate is not null', 16, 1);
end
END
I need to create MySQL trigger that would log user ID on delete table row statement which must fit in one query, since I'm using PHP PDO. This is what I've come up so far:
I need the way to pass user ID in the delete query even though it is irrelevant to delete action to be performed:
Normally the query would look like this:
DELETE FROM mytable WHERE mytable.RowID = :rowID
If I could use multiple queries in my statement, I would do it like this:
SET #userID := :userID;
DELETE FROM mytable WHERE mytable.RowID = :rowID;
This way the variable #userID would be set before trigger event fires and it can use it. However since I need to squeeze my delete statement in one query, so I came up with this:
DELETE FROM mytable
WHERE CASE
WHEN #userID := :userID
THEN mytable.RowID = :rowID
ELSE mytable.RowID IS NULL
END
Just a note: RowID will never be null since it's the primary key. Now I have to create a delete trigger to log the user ID to the audit table, however I suppose that in this case trigger will be fired before the delete query itself which means that #userID variable will not be created? This was my idea of passing it as a value to the trigger.
I feel like I'm close to the solution, but this issue is a blocker. How to pass user ID value to the trigger without having multiple queries in the statement? Any thoughts, suggestions?
You can use NEW / OLD mysql trigger extensions. Reference: http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
Here is a sample code :
drop table `project`;
drop table `projectDEL`;
CREATE TABLE `project` (
`proj_id` int(11) NOT NULL AUTO_INCREMENT,
`proj_name` varchar(30) NOT NULL,
`Proj_Type` varchar(30) NOT NULL,
PRIMARY KEY (`proj_id`)
);
CREATE TABLE `projectDEL` (
`proj_id` int(11) NOT NULL AUTO_INCREMENT,
`proj_name` varchar(30) NOT NULL,
`Proj_Type` varchar(30) NOT NULL,
PRIMARY KEY (`proj_id`)
);
INSERT INTO `project` (`proj_id`, `proj_name`, `Proj_Type`) VALUES
(1, 'admin1', 'admin1'),
(2, 'admin2', 'admin2');
delimiter $
CREATE TRIGGER `uProjectDelete` BEFORE DELETE ON project
FOR EACH ROW BEGIN
INSERT INTO projectDEL SELECT * FROM project WHERE proj_id = OLD.proj_id;
END;$
delimiter ;
DELETE FROM project WHERE proj_id = 1;
SELECT * FROM project;
SELECT * FROM projectDEL;