I am working on a legacy system that generates confirmation numbers based on the ID of their order record in the database. It's just a bunch of zeros append to the front of the row ID which is created automatically using auto increment. Currently the system is inserting the order into the database and then immediately doing an update to add the confirmation number (after getting the insert ID programmatically).
I'd like to reduce this second step if at all possible by adding the confirmation number when the order is placed. However, I am unaware of how this can be done, or if it can be done, via SQL. Is this possible? If so, how? I've Googled this but I just get results telling me how to get the last insert ID after the query has already run.
You can write a trigger that is execute where order is inserted.
Sample:
CREATE TRIGGER order_zeros BEFORE INSERT ON orders
for each row
begin
SET NEW.confirmation = LPAD( NEW.id, 8, '0' );
end;
Disclaimer: this code is not tested, only to explain solution.
Related
Hey guys a little question for you.
I'm currently working on SQL Triggers and my goal is to archive logging if there are changes made to our database. For example we got some tables like customers with: name, firstname, placeofbirth and so on. We offer the users to update their own data and want to save the OLD data in a new table for logging reasons. To have only one logging table for all updates the logging table is kind of generic with:
id, timestamp, table_name, column, old_value, new_value.
table_name is the updated table, colum the updated column in this table and all the rest should speak for itself. Therefore it would be great to know not only in which tuple but also in which particular column the update has happened.
My question: Is there a construct like:
create trigger logging_trigger on customer**.firstname** after insert ...
to trigger an action only if there happened an update on let's say the 'firstname' column?
If not is there a smooth solution for handling all possible update cases?
Thank you.
I use a format like you described in my system... Below is how I accomplish it with your required logic.
CREATE DEFINER = CURRENT_USER TRIGGER `testing_schema`.`new_table_BEFORE_UPDATE` BEFORE UPDATE ON `new_table` FOR EACH ROW
BEGIN
IF NEW.ColumnName <> OLD.ColumnName THEN
INSERT INTO HistoryTable (`ColumnName1`, `ColumnName2`, ect..) VALUES (OLD.ColumnName1, OLD.ColumnName2, ect...);
END IF;
END
The main difference In mine is, that I do not have an IF condition. I simply copy the entire row to the history table every time an Update/Delete is made to that row. That way I don't have to maintain any form of logic to handle scenarios of investigating "what changed", I just save the entire row because I know "something" changed.
Am populating a table using a trigger after an insert event occurs on another table and that worked fine. However i then noticed that the trigger would still insert a new row for existing records. To fix this, I want to create the trigger again but this time it would only fire if a condition is met...but not having previously used triggers in the past am getting a syntax error and not able to identify what am doing wrong. Kindly have a look and help me fix this
CREATE TRIGGER `students_gen_insert`
AFTER INSERT ON `students` FOR EACH ROW
BEGIN
INSERT INTO records (student_id, subject_id)
SELECT new.student_id, subjects.subject_id
FROM subjects
WHERE category = new.class;
END;
Am currently using MySql 5.6.17 version.
It is generally not a good idea to SELECT from the table the trigger is on, and forbidden to UPDATE or INSERT (not that you are doing those). Assuming you are trying to get the values for the row just inserted, the first SET ... SELECT you have is needless; just use NEW.fieldname to get the fields of the inserted row.
The second SET ... SELECT and following condition are a bit confusing. If referential integrity is being maintained, I would think it would be impossible for the records table to refer to that particular student_id of the students table at the point the trigger is executed. Perhaps this was to avoid the duplicate inserts from the trigger's previous code? If so, it might help for you to post that so we can pinpoint the actual source of redundant inserts.
I have a table named Warehouse for my database, it has Warehouse_idWarehouse and Warehouse_name as primary keys. What i want to do is to efficiently store a maximum of N recent changes that have been made to each warehouse that is stored in the table. I have considered creating a "helper" table (e.g. warehouse_changes) and taking care of the updates through my application, but honestly it feels like there is a smarter way around this.
Is there a way to store a specific amount of entries per warehouse and automatically manage updating the right element through mysql workbench? Thanks in advance and keep in mind that i'm not particularly advanced in this field.
There is a very detailed article on O'Reilly Answers that describes how to do exactly what you want using triggers.
When explained in two words, you need to create a helper table and a trigger per each operation type that you want to store. For example, here's how a trigger for updates looks like according to that article:
-- Creating a trigger that will run after each update
-- for each affected row
CREATE TRIGGER au_warehouse AFTER UPDATE ON Warehouse FOR EACH ROW
BEGIN
-- Insert new values into a log table, or you can insert old values
-- using the OLD row reference
INSERT INTO warehouse_log (action, id, ts, name)
VALUES('update', NEW.id, NOW(), NEW.name);
END;
After that you can get the latest 1000 changes using a simple SQL query:
SELECT * FROM warehouse_log ORDER BY ts DESC LIMIT 1000;
I'm trying to generate unique id using php for a table ex: 2013-10-24-01 (yyyy-mm-dd-last_index_plus_1).
The problem is, if there are two session simultaneous open the php
which is access a same table, the generate unique id will be same on them.
I come up with idea that determined the number of session accessing that table
and then plus the last_index by that number,
but i don't know how to accomplished it with mysql.
Is it possible or not?
Thanks
As noted in the comment I am not sure why you want PHP to actually do this, and why the auto_increment is not good enough, but if you need a unique ID you can do the following:
Make sure to add a unique key on the column you are inserting into - if something goes wrong your database will make sure you won't get the two identical keys. In theory you could try until the query succeeds from PHP
You can use the "select for update" (http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html) when selecting the last known sequence to make sure that another process will not try to read before you have inserted it.
The above is possible to do in mysql using a trigger, as you did not provide any structure, the below is just an example of how it could look. It uses a sequence-table for selecting the last id, and the mysql date_format function to format the inserted date.
delimiter |
create trigger `trigger_name`
before insert on `table_name`
for each row begin
set new.last_id = concat(date_format(now(), '%y-%m-%d'), '-', (select max(id) from `sequence_table` for update));
end|
delimiter ;
I'm trying to find the most effecient way of inserting data into another table when a particular field is updated on trigger table. The INSERT should only occur on a specific type of update.
The table on which I want to create the trigger is named incremental. The table I'm inserting into is named crm_record
On incremental there is a field called status. By default when a record is initially added to the table the status field is set to new. After billing has processed that value changes to processed. So once this occurs I want to INSERT into crm_record, only if the value of another field (success) is set to 1.
I have considered using both CASE and IF but would like an expert's opinion on the best way to do this.
Ok, I eventually went with this that seemed to work. Thanks for pointing me in the right direction
CREATE TRIGGER `incremental5_after_ins_tr_crmm` AFTER UPDATE ON `incremental5`
FOR EACH ROW
BEGIN
IF Status = 'processed' AND Success = 1 THEN
INSERT INTO crm_master (msisdn,source,contract_type,revenue) VALUE (new.msisdn,'INC5',new.contract_type,revenue=revenue+2.5)
ON DUPLICATE KEY UPDATE contract_type=new.contract_type,revenue=revenue+2.5;
END IF;
END;
All you need to do is to create an AFTER UPDATE trigger and test the value of status and success together. If it's going only going to be one state you're testing for then an IF statement would be the simplest way to go about it.
However before implementing a trigger it's always worth going back a step and checking to see if the row in crm_record shouldn't actually be inserted via the code logic when the status and success columns are updated.