I have a MYSQL database with a table like:
Id myId Description
ABD1 0 some desc
ABD2 1 some desc
....
myId is an autoincremented column. I need to create a mysql trigger that will prevent anyone from changing the first myId value assigned to a row at the time of its insertion. How can this be done in mysql? I was thinking:
CREATE TRIGGER upd_check BEFORE UPDATE ON myTable
FOR EACH ROW
BEGIN
NEW.myId = OLD.myID
END
Could this be enough? If so, is this trigger going to run for all rows of my table? only for the new ones? I just need for one row.
Thx
To answer your question directly:
Could this be enough?
Yes, this will make sure any UPDATE will not change the value of your myID column. It will always reset that column to the value it was prior to the UPDATE.
If so, is this trigger going to run for all rows of my table? only for the new ones?
The answer is in the manual page https://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html which says:
The statement following FOR EACH ROW defines the trigger body; that is, the statement to execute each time the trigger activates, which occurs once for each row affected by the triggering event.
In other words, the trigger executes once for each row matching the condition in your UPDATE's WHERE clause.
It will not apply to every row in the table—unless your WHERE clause matches every row.
Related
I need to create a trigger in mySQL that uses the auto incremented id to fill another column.
Let's say the id is "12", i need another column to be automatically filled with "12-xxx".
I'm trying to do that using an before insert trigger but it is not working.
CREATE TRIGGER TR_CARTAO_BI BEFORE INSERT ON CARTAO FOR EACH ROW
BEGIN
SET NEW.NUMERO = CONCAT(NEW.IDCARTAO, '-XXX');
END $$
It seems that I can't use the id in the before insert trigger because it hasn't been generated yet;
I heard about the query "SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES..." that returns the next auto increment element but sometimes it works, sometimes it doesn't;
I tried to use an after insert trigger but apparently you can't change the row that you are inserting in the after insert trigger;
From your question it looks like you've exhausted all possible routes (I would have initially suggested the SELECT AUTO_INCREMENT query, but this isn't reliable for you) that avoid using a secondary table.
So, as a hacky work-around, you could try this instead... You could use an AFTER INSERT trigger to create a row in a secondary table, which would have the ID of the row you just created and your secondary column with the ID-XXX value. On the secondary table, set up an AFTER INSERT trigger to update your primary table row with the ID-XXX value.
This could be expensive, depending on your use-case and velocity of transactions etc. But I thought I'd offer lateral thinking...
Want to Insert multiple rows into table "txn_dbtransactionnotification" when new data is inserted/update into the "Txn_Sales" table.
Suppose 5 rows are present into the transaction table "Txn_Sales" and 1 row into the master table "Mst_Sales".
So when Data into the master table "Mst_Sales" is modified then related data into the table "Txn_Sales" must be modified and the update be sent to the table "txn_dbtransactionnotification" so how can I use a Cursor inside a Trigger so when data in table "Mst_Sales" is modified then data into the table "Txn_Sales" must be modified row by row.
Cursor support is incomplete in MySQL's stored routine language. It does not support UPDATE ... WHERE CURRENT OF CURSOR like some other brands of SQL implementation.
But in many cases, it's not necessary to update row by row. It's simpler to update a batch. Think of updating sets of rows, instead of row by row.
For example:
CREATE TRIGGER mytrigger AFTER UPDATE ON Mst_Sales
FOR EACH ROW
BEGIN
-- update a set of rows related to the same product that
-- spawned this trigger.
UPDATE Txn_Sales SET price = NEW.price WHERE product = NEW.product;
-- and enter a record in the notifications table
INSERT INTO txn_dbtransactionnotification ...;
END
I had to imagine what type of update you were talking about, because you described the problem in such an abstract way. In a real-life scenario, I don't think changing the price of a product would apply retroactively to past transactions. So the example above is only to show the technique, not the real code you would use.
I'm new to SQL so I don't understand why this this query is not working. Thank you in advance
CREATE VIEW temp AS
SELECT return_date_time, renting_date_time
FROM renting;
CREATE TRIGGER charge_calc AFTER UPDATE ON renting.return_date_time
FOR EACH ROW
BEGIN
UPDATE renting
SET new.charge =(select m.charge_per_day
from movies m,renting as r
where (m.id=r.id_movie))*datediff(temp.return_date_time,temp.renting_date_time);
END
DATA DIAGRAM
I don't think you should run the update of the charge on that way; if you're wanting to set the values of a row in a trigger that is firing because the row has been updated, all you need to do is
SET new.columnname = somevalue
To set the value of columnname on the updated row. You don't kick off another update of the table within the update trigger that is firing upon update of the table.
Next, you seem to be joining all the rows in movies together with all the rows in renting, which will surely return hundreds or thousands of rows, and you're trying to set one value. This is broken logic: which of the thousands of movie rows do you want MySQL to pick? It won't choose; the logic is broken
Step back for moment and consider: this is an update trigger of the renting table. It fires for every row updated and the row being updated is accessible by the new. specifier. There is a new.movie_id property - that's the id of the movie being updated right now. If you want some data out of the movies table, select it based on the movie id in the new row (the row being updated) I.e. new.movie_id
You don't need the temp view either - if you want to know the return date, surely that is also part of the new. row
All in, this trigger should probably be a single line along the following idea:
SET new.charge = (select rate from movies where id = new.movie_id) * datediff(date_rented, date_returned, day)
As a side comment, I think the front end app should be doing this, not triggers in the database
I need to set a maximum limit of rows in my MySQL table. Documentation tell us that one can use following SQL code to create table:
CREATE TABLE `table_with_limit`
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB MAX_ROWS=100000
But MAX_ROWS property is not a hard limit ("store not more then 100 000 rows and delete other") but a hint for database engine that this table will have AT LEAST 100 000 rows.
The only possible way I see to solve the problem is to use BEFORE INSERT trigger which will check the count of rows in table and delete the older rows. But I'm pretty sure that this is a huge overheat :/
Another solution is to clear the table with cron script every N minutes. This is a simplest way, but still it needs another system to watch for.
Anyone knows a better solution? :)
Try to make a restriction on adding a new record to a table. Raise an error when a new record is going to be added.
DELIMITER $$
CREATE TRIGGER trigger1
BEFORE INSERT
ON table1
FOR EACH ROW
BEGIN
SELECT COUNT(*) INTO #cnt FROM table1;
IF #cnt >= 25 THEN
CALL sth(); -- raise an error
END IF;
END
$$
DELIMITER ;
Note, that COUNT operation may be slow on big InnoDb tables.
On MySQL 5.5 you can use SIGNAL // RESIGNAL statement to raise an error.
Create a table with 100,000 rows.
Pre-fill one of the fields with a
"time-stamp" in the past.
Select oldest record, update "time-stamp"
when "creating" (updating) record.
Only use select and update - never use insert or delete.
Reverse index on "time-stamp" field makes
the select/update fast.
There is no way to limit the maximum number of a table rows in MySQL, unless you write a Trigger to do that.
I'm just making up an answer off the top of my head. My assumption is that you want something like a 'bucket' where you put in records, and that you want to empty it before it hits a certain record number count.
After an insert statement, run SELECT LAST_INSERT_ID(); which will get you the auto increment of a record id. Yes you still have to run an extra query, but it will be low resource intensive. Once you reach a certain count, truncate the table and reset the auto increment id.
Otherwise you can't have a 'capped' table in mysql, as you would have to have pre-defined actions like (do we not allowe the record, do we truncate the table? etc).
I have an id column which is a primary key with AUTO_INCREMENT. I need the value that is generated to be inserted into the id column, as well as another column (which isn't set to AUTO_INCREMENT, and isnt unique.
Currently I use the mysqld_isnert_id() function to get the id, and simply run an update query after the insert, but I was wondering if I could do this without running the 2nd update query.
after insert Trigger?
If I recall correctly, the automatically generated ID isn't even created until after the insert has been performed. Your two query way is probably the only way without diving into perhaps a stored procedure.
You could define a trigger along the lines of:
delimiter //
CREATE TRIGGER upd_check AFTER INSERT ON mainTable
FOR EACH ROW
BEGIN
UPDATE dependingTable
SET dependingTable.column = NEW.id
END;//
delimiter ;
I am not exactly sure WHEN the AUTO_INCREMENT value is generated, but you could try the following, since if it works it'll save you an update (If the column you want the value replicated to is in the same row as the inserted row):
CREATE TRIGGER upd_check BEFORE INSERT ON mainTable
FOR EACH ROW
SET NEW.column = NEW.id
The only way I can see you doing it with a single query is to use the information schema. In the information schema there is a table called 'tables', there you access the column auto_increment. That contains the NEXT insert id for that table, you can access this via a nested select, just give the user used to connect to the database read access to that table. This will only work with innodb engines as far as I can tell as that way the nested select you'll do to populate the second id field will be part of the greater transaction of the insert.
That's what your query might look like:
INSERT INTO fooTable VALUES (0, (SELECT AUTO_INCREMENT FROM information_schema.TABLES));
Also if you're worried about read access and security issues, just remember this is the same info you can get by running a show table status. Speaking of which, I tried to see if you could project the show commands/queries via a select and you can't, which totally sucks, because that would have been a much cleaner solution.