I am working on a project where I need my ID column to be a power of 2 (1,2,4,8,16..). I know that we cannot offset the auto_increment but for simple addition/subtraction in my.cnf.
Example:
id
----
1
2
4
8
16
32
64
128
etc
One of the ideas I had was to use the auto increment functionality as the base, and then create a trigger to apply the power of 2 and update the new ID, but unfortunately, it is not working:
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET NEW.id = pow(NEW.id, 2)
END;
$$
DELIMITER ;
Because the BEFORE INSERT has not yet generated the AUTO_INCREMENT id, the AUTO_INCREMENT will always return 0, essentially causing no change on the columns.
I also tried AFTER INSERT:
DELIMITER $$
CREATE TRIGGER testbitcompatid AFTER INSERT ON Table
FOR EACH ROW
BEGIN
SET Table.id = pow(NEW.id, 2) WHERE id = NEW.id;
END;
$$
DELIMITER ;
But this failed because you cannot change values of the table which the trigger is applied to during an AFTER INSERT.
Scratching my head, but I am sure someone else has a great way of accomplishing this.
To work around all the issues above, I was able to construct the following which works great!
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET #LAST_ROW = (SELECT MAX(id) FROM Table);
SET NEW.id = CASE WHEN #LAST_ROW IS NULL THEN 1 ELSE #LAST_ROW * 2 END;
END;
$$
DELIMITER ;
Pretty much, we take the highest id, grab the log(2) of it which gives us the corresponding AUTO_INCREMENT id. We then add 1, and power that up to 2.
I hope this helps prevent some headache down the road for others.
Related
I want to add a limit to how many items my table can have. I want the maximum amount of items to be 10. I want it to only be 10 people in my table. I dont want it to be able to add items after the 10th person. Here is my code:
CREATE TABLE person (
name VARCHAR(233) NOT NULL,
number int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(number),
Check(number>10))
delimiter //
create trigger limit_persons before insert on person for each row
begin
declare count integer
select COUNT(*) FROM person INTO count;
if count>=10 then
signal sqlstate '45000' set message_text = 'Limit exceeded';
end if;
end
//
I would advise to handle such stuff as limitations in the software itself. So you have control over it later and it is overall a cleaner solution. But you can try this, if you really want to limit it in mysql:
ALTER TABLE tbl_name MAX_ROWS=10 AVG_ROW_LENGTH=nnn;
You can also check out triggers and signals:
https://dev.mysql.com/doc/refman/5.5/en/signal.html
https://dev.mysql.com/doc/refman/5.5/en/trigger-syntax.html
You can set up a trigger (to be specific, an Insert trigger) that counts the records and, if count is more than 10, it does not allow the insert operation.
Following code will be helpful to you,
DELIMITER $$
CREATE TRIGGER LimitRowCountTrigger
BEFORE INSERT
ON person
FOR EACH ROW
BEGIN
SELECT COUNT(*) INTO #cnt FROM person;
IF #cnt > 10 THEN
CALL sth(); -- raise an error
END IF;
END
$$
DELIMITER ;
I have a question about MySQL triggers—say I have the following table:
CREATE TABLE test (
id INT(6),
value_1 INT(6),
value_2 INT(6),
values_were_set BOOL
)
Now, every time I insert a value into this table I want to have a trigger check if value_1 and value_2 have been set. And if they are, it should set values_were_set to true.
NULL values are allowed.
How would I go about this? In the real table there are about ten columns that I want to check for, so I would fancy not to have to use a bunch of IF statements.
Maybe it's better to do it in the app?
Then trigger it is:
DELIMITER $$
CREATE TRIGGER value_check BEFORE INSERT ON test
FOR EACH ROW
BEGIN
IF NEW.value_1 IS NOT NULL AND NEW.value_2 IS NOT NULL THEN
SET NEW.values_were_set = 1;
ELSE
SET NEW.values_were_set = 0;
END IF;
END;
$$
Unfortunately yes, I think you would need a nasty if/else section in the trigger if you want to check multiple combinations of fields
I would like to create a table with an incremental counter, let's say from 14 to 17. The table should look like:
counter
14
15
16
17
Obviously, the range I really need is much larger. Any idea? I use MySQL.
Use the following stored procedure.
(change t1 to your table name)
DELIMITER $$
CREATE DEFINER=`server`#`%` PROCEDURE `test1`(start_num INT, end_num INT)
BEGIN
WHILE start_num < end_num DO
INSERT INTO t1 VALUES(start_num);
SET start_num = start_num + 1;
END WHILE;
END$$
Create an auto_increment column. See http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
I have a table called customer which has, among others, a column called name and a column called first_name_start. I want first_name_start to be equal to SUBSTRING(name, 1, 4). How would I create a trigger that makes sure this happens?
DELIMITER $$
CREATE TRIGGER trigger_name BEFORE INSERT ON your_table
FOR EACH ROW
BEGIN
SET NEW.first_name_start = SUBSTRING(NEW.name, 1, 4);
END$$
CREATE TRIGGER trigger_name BEFORE UPDATE ON your_table
FOR EACH ROW
BEGIN
SET NEW.first_name_start = SUBSTRING(NEW.name, 1, 4);
END$$
DELIMITER ;
Unfortunately, I didn't get time to test this, it might be completely wrong.
Why not just make a view which adds the first_name_start if you really need it as a column? Then you won't be storing redundant data, but you will be able to use it as if you were.
I have an issue with a trigger on a mysql database. I have a table such as follows:
id int not null auto_increment (PK)
parent_id int not null,
rank int not null
What I'm trying to do is use a trigger to update the rank to the next highest +10 when they have the same parent_id, but this doesn't seem to be working.
DELIMITER $$
DROP TRIGGER IF EXISTS after_insert $$
create trigger after_insert
after insert on mytable
FOR EACH row
BEGIN
IF EXISTS (SELECT rank FROM mytable WHERE parent_id = new.parent_id AND id != new.id ORDER BY rank DESC LIMIT 1) THEN
UPDATE mytable SET rank = 10
WHERE id = new.id;
ELSE
UPDATE mytable SET rank = 20
WHERE id = new.id;
END IF;
END
$$
I've tried setting the new rank to a variable and calling the update statement using that, and again it didn't work. I even created another table to log what values were being selected and that worked perfectly so I can't quite understand what's going on. Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted? Another reason I ask this is, I've even tried updating the rank to different values e.g 1 and 2 depending on which statement it goes to, but it always ends up being 0.
I think you're on the right track with this thought:
Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted?
From the FAQ:
B.5.9: Can triggers access tables?
A trigger can access both old and new data in its own table. A trigger can also affect other tables, but it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
The documentation isn't clear that what you're doing won't work. OTOH, the documentation isn't clear that what you're trying to do will work either.
I think you'd be better off using a BEFORE INSERT trigger and setting NEW.rank in there. Then, the new row would have the right rank value when it is actually inserted into the table rather than patching it after. Also, you'd be able to simplify your existence check to just this:
EXISTS(SELECT rank FROM mytable WHERE parent_id = new.parent_id)
as NEW.id wouldn't have a useful value and the new row wouldn't be in the table anyway; the ORDER BY and LIMIT are also unnecessary as you're just checking if something exists so I took them out.
A BEFORE INSERT trigger seems to match your intent better anyway and that will give you correct data as soon as it is inserted into your table.
If you want the rank to be set +10 more than highest "brother's" rank, you could use:
DELIMITER $$
DROP TRIGGER IF EXISTS whatever $$
create trigger whatever
BEFORE INSERT ON mytable
FOR EACH row
BEGIN
SET NEW.rank = 10 + COALESCE(
( SELECT max(rank)
FROM mytable
WHERE parent_id = NEW.parent_id
), 0 ) ;
END
$$