MySQL Trigger to auto insert week of the year and 001 (autoincrement) - mysql

I'd like to set a MySQL trigger to set an ID number with the following format:
week of the year + 001
For example 09002 would be the 9th week of the year and 002 would be the second order for that week.
Any help, comment would be greatly appreciated, Thanks.

USE CONCAT WITH MYSQL DATE FUNCTION WEEK
select CONCAT('0',WEEK(now()),'002');
+-------------------------------+
| CONCAT('0',WEEK(now()),'002') |
+-------------------------------+
| 029002 |
+-------------------------------+
1 row in set (0.05 sec)
DROP TRIGGER IF EXISTS TEST_INSERT;
DELIMITER $$
CREATE TRIGGER TEST_INSERT AFTER INSERT ON TEST FOR EACH ROW BEGIN
NEW.ID= CONCAT('0',WEEK(now()),'002')
-------------------- your insert statement ----------
END$$

Doing this with a trigger is a problem in MySQL because MySQL doesn't have a SEQUENCE object, like some other SQL databases have. You can't generate an incrementing id value in a trigger, it must be generated to populate an integer column that has the AUTO_INCREMENT option.
So here's an unconventional solution: don't think of using a trigger for this, use the primary key. At the start of each week, run a scheduled job to advance the next auto-increment number.
ALTER TABLE mytable AUTO_INCREMENT = WEEK(NOW())*1000;
You can do this from a cron job, or you can use the MySQL Event Scheduler.
I would also comment that you can't rely on the incrementing id being consecutive. You could have inserts that fail, or you could have some inserts be part of transactions that roll back, or you could have later deletions. All these would eliminate a row with a certain id value, and you shouldn't re-use id values.

Related

How do I set a column to be unique, but only under a condition?

I have a table, which has an ID, a column "A" and other columns. If A is set to "this", there can't be another ID with it's column A set to "this". Else, there can be many entries of that ID with multiple values set for column "A".
Ex.:
ID | A | other columns
this is allowed:
1 | that | ...
1 | something | ...
1 | foo | ...
but this is not:
1 | this | ...
1 | that | ...
(the 3 dots mean it doesn't matter what data we have there)
I'm doing this on MySQL Workbench, so it would be much appreciated if your answer showed me how to do it there.
You need to create a trigger that will fire before every INSERT or UPDATE statement (for each row) and check whether or not your constraint is valid and the row can or cannot be added. AFAIK in MySQL you actually need to have two triggers (one for each action), but there is nothing stopping you from wrapping up your validation within a procedure and call it from both triggers.
I'll give you the starters for further tweaking.
1.Create insert trigger
DELIMITER //
DROP TRIGGER IF EXISTS insert_trg //
CREATE TRIGGER insert_trg
BEFORE UPDATE ON yourtable
FOR EACH ROW
BEGIN
CALL yourprocedure(<arguments here>);
END //
DELIMITER ;
2.Create update trigger analogously to the insert trigger
3.Create procedure with the validation code
SQL to validate your constraint will look something like:
SELECT *
FROM yourtable yt
WHERE yt.id = NEW.id -- replace with arguments passed to procedure
AND yt.A = NEW.A -- same as above
You most likely need to wrap it up with an EXISTS statement and if statement
Some source of knowledge:
Trigger Syntax and Examples
Create Procedure Syntax

MySQL - Trigger on Insert HOUR('time')

I have a table that contains a field 'timeduration'. Currently when I select the 'timeduration' value I'm doing HOUR('timeduration') to get the time in hours. I would like to do this calculation when inserting the data into the table, so putting the hour value into it's own column.
| date | timeduration | hour
12-12-14 01:00:00 1
I've looked into triggers but not sure how to about this, or os there an easier way I'm missing?
Thanks for your help!
Yes, a BEFORE INSERT and BEFORE UPDATE trigger would do it. And that's the only way to get MySQL to automatically populate the value in the hour column, based on the value assigned to the timeduration column.
Here's an example a BEFORE INSERT trigger.
DELIMITER $$
CREATE TRIGGER mytable_bi
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
SET NEW.hour = HOUR(NEW.timeduration);
END$$
DELIMITER ;
You'll likely also want a corresponding BEFORE UPDATE trigger, if you want to keep hour in sync when timeduration value is modified by UPDATE statement.

Identifying the edited columns in the database

At the beginning the application have an admins and employees and records.
The records table has many columns than can be changed by any employee. However, this change can not be submitted. When the admin approve for an edit the record will show up again in the system.
I was trying to identify the column name and the value, and send it to another table using triggers on UPDATE.
So when the employee edits any record, the record will be disabled in the system. Also the admin will be able to know which values has been changed.
Is this possible in databases ?
Records Table
-------------------------------------------------------------------
record_id record_name record_serial record_active
-------------------------------------------------------------------
1 something 5151 YES
When an update happens to the record_serial, such as from 5151 to 9844 I need to do this.
Records_changes
-------------------------------------------------------------------
change_id record_col record_old_val record_new_val
-------------------------------------------------------------------
1 record_serial 5151 9844
At the same time
-------------------------------------------------------------------
record_id record_name record_serial record_active
-------------------------------------------------------------------
1 something 9844 NO
I can do it using my application, but if there is anyway to do it using the database it would be much nicer.
I will use this to track the changes, and also create a history for the records old values.
I am using MySQL
You can do something like this
DELIMITER $$
CREATE TRIGGER tg_bu_records
BEFORE UPDATE ON records
FOR EACH ROW
BEGIN
IF NOT (OLD.record_serial <=> NEW.record_serial AND
OLD.record_name <=> NEW.record_name) THEN
SET NEW.record_active = 0;
END IF;
END$$
CREATE TRIGGER tg_au_records
AFTER UPDATE ON records
FOR EACH ROW
BEGIN
IF NOT (OLD.record_serial <=> NEW.record_serial) THEN
INSERT INTO records_changes (record_col, record_old_val, record_new_val)
VALUES ('record_serial', OLD.record_serial, NEW.record_serial);
END IF;
IF NOT (OLD.record_name <=> NEW.record_name) THEN
INSERT INTO records_changes (record_col, record_old_val, record_new_val)
VALUES ('record_name', OLD.record_name, NEW.record_name);
END IF;
END$$
DELIMITER ;
Note: The trick is to change record_active flag in BEFORE trigger because it's the only event when you can change values of a row being updated/inserted in a table on which you defined that trigger. Now in AFTER trigger we record the changes that have been made.
Here is SQLFiddle demo
A good database pattern for this, if I understand your problem correctly, is to use versioned rows. You add columns (or additional referenced tables) with meta data about when/who/what the edit was about. When a record is edited, a new row is inserted. Previous versions are never modified or deleted. Then it's up to your application logic to decide what to do with all of this.

After insert trigger can do an update?

I'm new to the creation of triggers but I need it since I'm using a persistent storage for some IDs.
I have the table RECEIPT with a column RECEIPT_ID
and the table CONFIG_DB with columns and values:
NAME VALUE
--------------- -----
NEXT_RECEIPT_ID 1
and I created this trigger
CREATE TRIGGER UPDATE_RECEPCION_ID
AFTER INSERT ON RECEIPT
FOR EACH ROW
BEGIN
UPDATE CONFIG_DB SET VALUE=VALUE+1;
END
;
I don't know if this is OK... all I want its that after I insert a new RECEIPT_ID the VALUE in CONFIG_DB increases by 1. Thank you very much.
EDIT: I work in Mysql Workbench 5.2.40 with Mysql Server 5.5.25
Use following query to create trigger
delimiter |
CREATE
TRIGGER `UPDATE_RECEPCION_ID`
AFTER INSERT ON `RECEIPT`
FOR EACH ROW BEGIN
UPDATE CONFIG_DB SET VALUE=VALUE+1
WHERE NAME='NEXT_RECEIPT_ID';
END;
|

InnoDB automatic actions

I'm using MySQL and InnoDB. I'm versioning all the table's records - the latest version of the record has a column called 'lv' set to 1 and the previous record for that ID that has an 'lv' column set to 1 has to be set to 0 now that there's a new version. I'm now doing two queries every time I insert a new record (version). Is there a way to make InnoDB do that automatically? Thank you for your input.
You could use a trigger?
This is untested, but I think something like this would be possible:
delimiter |
CREATE TRIGGER newversion BEFORE INSERT ON yourTable
FOR EACH ROW BEGIN
UPDATE yourTable SET lv = 0 WHERE lv = 1;
END;
|
delimiter ;
There could be some mistake in there, as it is a quick type, based on the manual ofcourse :)