I'm designing a comments MySQL db, and my comments table has fields:
id primary key, auto-incr
thread int, not null
content
All replies to the same comment, in addition to that root comment must share the same thread. This is simple when a user is replying to a comment but what about when a new root comment is posted? I figured I would set thread=id for root comments.
Problem is, I don't know how to write a query that will reuse the just created id value within the same query when filling thread. Is this even possible?
I've tried
INSERT INTO `comments`
VALUES (NULL, LAST_INSERT_ID(), 'hi there')
This gives me the id from the previous insert, not the current one. Do I have to use 2 queries?
Do I have to use 2 queries?
Yes. As you discovered, the id value hasn't been generated yet in a BEFORE INSERT trigger. But you can't change your NEW.thread value in an AFTER INSERT trigger.
You can't rely on reading the INFORMATION_SCHEMA, because you can cause a race condition.
You'll just have to do the INSERT, and then immediately execute:
UPDATE comments SET thread=id WHERE id=LAST_INSERT_ID() AND thread IS NULL;
If it's a root comment.
See also my past answers on the similar topic:
Concatenating a string and primary key Id while inserting
Two autoincrements columns or autoincrement and same value in other column
Thanks to Michael's answer I started looking into triggers; basically event-handlers that run some code when something happens. Michael's trigger didn't work for me, but the following does:
USE `my_db_name`;
DELIMITER $$
CREATE TRIGGER comments_bi
BEFORE INSERT ON `comments`
FOR EACH ROW
BEGIN
DECLARE nextID INT DEFAULT 0;
SELECT AUTO_INCREMENT INTO nextID FROM information_schema.tables
WHERE table_name = 'comments' AND table_schema = DATABASE();
IF NEW.`thread` IS NULL OR NEW.`thread` = 0 THEN
SET NEW.`thread` = nextID;
END IF;
END $$
DELIMITER ;
One big caveat: because this trigger requires access to the information_schema, only the root account could define it.
Thanks to this answer for inspiration
You can simply set thread to NULL to signify that the comment is a root comment rather than attached to a thread.
Related
I'm designing a comments MySQL db, and my comments table has fields:
id primary key, auto-incr
thread int, not null
content
All replies to the same comment, in addition to that root comment must share the same thread. This is simple when a user is replying to a comment but what about when a new root comment is posted? I figured I would set thread=id for root comments.
Problem is, I don't know how to write a query that will reuse the just created id value within the same query when filling thread. Is this even possible?
I've tried
INSERT INTO `comments`
VALUES (NULL, LAST_INSERT_ID(), 'hi there')
This gives me the id from the previous insert, not the current one. Do I have to use 2 queries?
Do I have to use 2 queries?
Yes. As you discovered, the id value hasn't been generated yet in a BEFORE INSERT trigger. But you can't change your NEW.thread value in an AFTER INSERT trigger.
You can't rely on reading the INFORMATION_SCHEMA, because you can cause a race condition.
You'll just have to do the INSERT, and then immediately execute:
UPDATE comments SET thread=id WHERE id=LAST_INSERT_ID() AND thread IS NULL;
If it's a root comment.
See also my past answers on the similar topic:
Concatenating a string and primary key Id while inserting
Two autoincrements columns or autoincrement and same value in other column
Thanks to Michael's answer I started looking into triggers; basically event-handlers that run some code when something happens. Michael's trigger didn't work for me, but the following does:
USE `my_db_name`;
DELIMITER $$
CREATE TRIGGER comments_bi
BEFORE INSERT ON `comments`
FOR EACH ROW
BEGIN
DECLARE nextID INT DEFAULT 0;
SELECT AUTO_INCREMENT INTO nextID FROM information_schema.tables
WHERE table_name = 'comments' AND table_schema = DATABASE();
IF NEW.`thread` IS NULL OR NEW.`thread` = 0 THEN
SET NEW.`thread` = nextID;
END IF;
END $$
DELIMITER ;
One big caveat: because this trigger requires access to the information_schema, only the root account could define it.
Thanks to this answer for inspiration
You can simply set thread to NULL to signify that the comment is a root comment rather than attached to a thread.
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
What I'm trying to achieve is, I want to automate the values of the table between the users and folders table. Since it's a many-to-many relationship I created the user_folders table. Currently the server (nodejs) gets the request with userid, clientfolderid and some an array of bookmarks (which are not important now). It checks if the user already has this folder, by selecting from the user_folders table and if it's not existing it inserts a new row into the folder table. Then it has to send another statement to insert into the user_folders table.
So I have to "manually" keep the users_folder table updated.I guess this is a common problem and wanted to know if there is a pattern or a proven solution? The odd thing is that MySQL automatically handles the deletion of rows with an AFTER DELETE trigger but there is no (at least that I know of) automation with an AFTER INSERT trigger.
As I already said an AFTER INSERT trigger could possibly solve it, but I think it's not possible to pass some extra parameters to the AFTER INSERT trigger. This would be the user_id and the folder_client_id in my case.
I was thinking of a solution that I could create another table called tmp_folder which would look like:
tmp_folder
-- id
-- title
-- changed
-- user_id
-- folder_client_id
Then create an AFTER INSERT trigger on this table which inserts into folders and user_folders and then removes the row from tmp_folder again. Would this be the right way or is there a better one?
I would basically do the same with the bookmarks and user_bookmarks table. The best thing would be if it's even possible to insert a folder then the owner into the user_folders table with user_id and folder_client_id and then multiple other users into user_folders with the user_id and an default folder_client_id of -1 or something which will be updated later.
Meanwhile thanks for reading and I hope you can help me :)
PS: Is there a name for the table between 2 other tables in an m-2-m relationship?
I don't see an easy way to do this via triggers, but a stored procedure may suit you:
DELIMITER //
CREATE PROCEDURE
add_user_folder(
IN u_user_id BIGINT UNSIGNED,
IN u_folder_client_id BIGINT UNSIGNED,
IN v_title VARCHAR(255)
)
BEGIN
DECLARE u_found INT UNSIGNED DEFAULT 0;
SELECT
1 INTO u_found
FROM
user_folders
WHERE
user_id = u_user_id AND
folder_client_id = u_folder_client_id;
IF IFNULL(u_found, 0) = 0 THEN
START TRANSACTION;
INSERT INTO
folders
SET
title = v_title,
changed = UNIX_TIMESTAMP();
INSERT INTO
user_folders
SET
user_id = u_user_id,
folder_id = LAST_INSERT_ID(),
folder_client_id = u_folder_client_id;
COMMIT;
END IF;
END;
//
MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END
MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END