MYSQL auto_increment_increment - mysql

I would like to auto_increment two different tables in a single mysql database, the first by multiples of 1 and the other by 5 is this possible using the auto_increment feature as I seem to only be able to set auto_increment_increment globally.
If auto_increment_increment is not an option what is the best way to replicate this

Updated version: only a single id field is used. This is very probably not atomic, so use inside a transaction if you need concurrency:
http://sqlfiddle.com/#!2/a4ed8/1
CREATE TABLE IF NOT EXISTS person (
id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY ( id )
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TRIGGER insert_kangaroo_id BEFORE INSERT ON person FOR EACH ROW BEGIN
DECLARE newid INT;
SET newid = (SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'person'
);
IF NEW.id AND NEW.id >= newid THEN
SET newid = NEW.id;
END IF;
SET NEW.id = 5 * CEILING( newid / 5 );
END;
Old, non working "solution" (the before insert trigger can't see the current auto increment value):
http://sqlfiddle.com/#!2/f4f9a/1
CREATE TABLE IF NOT EXISTS person (
secretid INT NOT NULL AUTO_INCREMENT,
id INT NOT NULL,
PRIMARY KEY ( secretid )
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
CREATE TRIGGER update_kangaroo_id BEFORE UPDATE ON person FOR EACH ROW BEGIN
SET NEW.id = NEW.secretid * 5;
END;
CREATE TRIGGER insert_kangaroo_id BEFORE INSERT ON person FOR EACH ROW BEGIN
SET NEW.id = NEW.secretid * 5; -- NEW.secretid is empty = unusuable!
END;

Related

MySQL Non Sequential ID

Challenge:
Create a method to set "auto_increment" values for tables in a non-sequential way.
The goal is to override the "auto_increment" mechanism and allow the function "LAST_INSERT_ID()" to continue working as expected (returning an INT), so that no changes are needed in software side.
My Solution
The method I found is based on an auxiliary table (unique_id), that stores values available to be assigned. Values are then selected randomly, and removed from the tables as used. When the table gets empty, a new set of ID's is created.
This example is working as expected, but with one problem.
Tables for the demo:
CREATE TABLE `unique_id` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=100;
CREATE TABLE `test_unique_id` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
Defined a stored procedure and a function:
DELIMITER $$
DROP PROCEDURE IF EXISTS `UNIQUE_ID_REFILL`$$
CREATE PROCEDURE UNIQUE_ID_REFILL()
BEGIN
DECLARE a INT Default 0 ;
simple_loop: LOOP
SET a=a+1;
INSERT INTO unique_id (id) values(null);
IF a=100 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$
DROP FUNCTION IF EXISTS `UNIQUE_ID_GET`$$
CREATE FUNCTION UNIQUE_ID_GET()
RETURNS INT(11)
MODIFIES SQL DATA
BEGIN
DECLARE new_id INT(11);
DECLARE unique_id_count INT(11);
SET new_id = 0;
SELECT COUNT(*) INTO unique_id_count FROM unique_id;
IF unique_id_count=0 THEN
CALL UNIQUE_ID_REFILL();
END IF;
SELECT id INTO new_id FROM unique_id ORDER BY RAND() LIMIT 1;
DELETE FROM unique_id WHERE id = new_id;
RETURN new_id;
END $$
Created a Trigger on the destination table (test_unique_id):
CREATE TRIGGER test_unique_id__unique_id BEFORE INSERT ON test_unique_id
FOR EACH ROW
SET NEW.id = UNIQUE_ID_GET();
The solution is getting the random ID's as expected:
INSERT INTO test_unique_id(name) VALUES ('A'),('B'),('C');
Creates the rows:
id name
154 'A'
129 'B'
173 'C'
The Problem
The main problem is that LAST_INSERT_ID() stops working... and the software side is broken:
SELECT LAST_INSERT_ID();
0
Any ideas on how to solve this problem? or any other different approach to the challenge?
Thank you very much.

How to insert multiple records from one table into another on update of third table in MySQL

I'm having difficulty with developing the logic in MySQL. I don't know how to INSERT multiple records from a Table AFTER UPDATE.
CREATE TABLE primeira(
ID int PRIMARY KEY AUTO_INCREMENT,
nome varchar(30) NOT NULL,
valor int DEFAULT 0
);
CREATE TABLE segunda(
ID int PRIMARY KEY AUTO_INCREMENT,
ID_primeira int,
ultimo_valor int DEFAULT 0,
credito int NOT NULL,
limite int DEFAULT 0,
FOREIGN KEY(ID_primeira) references primeira(ID)
);
CREATE TABLE terceira(
ID int PRIMARY KEY AUTO_INCREMENT,
ID_segunda int,
`data` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
estado boolean DEFAULT false,
FOREIGN KEY(ID_segunda) references segunda(ID)
);
CREATE TRIGGER tr_segundaLimite_INS
BEFORE INSERT ON segunda FOR EACH ROW
SET NEW.limite = New.ultimo_valor + New.credito;
DELIMITER //
CREATE TRIGGER tr_primeira_UPD
AFTER UPDATE ON primeira FOR EACH ROW
IF (SELECT limite FROM segunda WHERE segunda.ID_primeira = New.ID AND
(limite - NEW.valor)< 50) THEN
INSERT INTO terceira(ID_segunda)
VALUES ((SELECT ID FROM segunda WHERE segunda.ID_primeira = New.ID
AND (limite - NEW.valor)< 50));
END IF;
END
//
DELIMITER ;
I'm going to use procedures with functions to SELECT the data. The problem with this TRIGGER is that it's not working when there are multiple matching records.
The error that I am getting is-
subquery returns more than 1 row.
The objective is: After an update of the primeira.valor, the trigger would subtract segunda.limite - New.valor. If this difference is < 50 then all the matching segunda.ID would be registered at terceira.ID_segunda on terceira table.
I'm using data below:
INSERT INTO primeira(nome,valor)
VALUES
('Burro',800),
('Chiconizio',300),
('Xerosque',400),
('Shrek',600);
INSERT INTO segunda(ID_primeira,ultimo_valor,credito)
VALUES
(1,600,800),
(1,700,400),
(1,800,500),
(2,150,200),
(2,200,180),
(2,250,300);
UPDATE primeira
SET Valor = 330
WHERE ID = 2;
You need CURSOR for this. You can try the following trigger code. I hope this will fix your issue.
DELIMITER //
CREATE TRIGGER tr_primeira_UPD
AFTER UPDATE ON primeira FOR EACH ROW
BEGIN
DECLARE v_limite_diff INT;
DECLARE v_seg_id INT;
DECLARE done INT DEFAULT FALSE;
DECLARE c1 CURSOR FOR SELECT (s.limite - NEW.valor), s.id
FROM segunda s WHERE s.ID_primeira = New.ID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN c1;
my_loop: LOOP
FETCH c1 INTO v_limite_diff, v_seg_id;
IF done THEN
LEAVE my_loop;
END IF;
IF( v_limite_diff < 50 ) THEN
INSERT INTO terceira(ID_segunda) VALUES(v_seg_id);
END IF;
END LOOP;
END//
DELIMITER ;

Skip certain number in mysql auto-increment

I've currently made a simple record table, with the recordID as the auto-increment primary key, the question is, due to religious reasons, my employer DOES NOT want to include the number 4 and 6 in the recordID, so instead of checking the recordID everytime after the record has been made, is there a much easier way to solve my current problem?
EDIT:
Here's a quick test table I've created based on Vanojx1's answer. So what did I do wrong?
CREATE TABLE `test` (
`ID` int(11) NOT NULL,
`value` int(11) NOT NULL
)
DELIMITER $$
CREATE TRIGGER `jump4and6` BEFORE INSERT ON `test` FOR EACH ROW BEGIN
SET #nextId = (SELECT MAX(`id`) FROM `test`);
IF (#nextId IN (4,6)) THEN
SET NEW.id = #nextId + 1;
SET #nextId = #nextId + 2;
ELSE
SET NEW.id = #nextId;
SET #nextId = #nextId + 1;
END IF;
INSERT INTO `test`(`id`) VALUES (#nextId);
END
$$
DELIMITER ;
ALTER TABLE `test` ADD PRIMARY KEY (`ID`);
ALTER TABLE `test` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT;
Everything works so far, but when I tried to insert a row:
INSERT INTO `test`(value) VALUES (123456);
This happens.
#1442 - Can't update table 'test' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
You can create the primary key as an integer, then use a trigger before insert like this:
DELIMITER $$
CREATE TRIGGER jump4and6
BEFORE INSERT
ON your_table
FOR EACH ROW BEGIN
SET #nextId = (SELECT MAX(current_index) FROM your_table_sequence);
IF (#nextId IN (4,6)) THEN
SET NEW.id = #nextId + 1;
SET #nextId = #nextId + 2;
ELSE
SET NEW.id = #nextId;
SET #nextId = #nextId + 1;
END IF;
INSERT INTO your_table_sequence (current_index) VALUES (#nextId);
END$$
You also need a table to store your primary key sequence

Trigger not working on MySQL

I am trying to create to trigger to divide my primary key into two groups.
Here is my table:
CREATE TABLE `q_locations` (
`id` int(11) NOT NULL,
`name` varchar(300) NOT NULL,
`standalone` bit(1) NOT NULL DEFAULT b'0',
UNIQUE KEY `id` (`id`),
KEY `standalone` (`standalone`)
)
If standalone is 0, id should start from 1, if standalone = 1, id should start from 1000. Id should be increment after each insert.
My trigger:
DELIMITER $$
CREATE TRIGGER trigger_insert_q_locations
BEFORE INSERT ON q_locations
FOR EACH ROW
BEGIN
SET New.id = (
SELECT coalesce(max(id) + 1, (case when standalone = 0 then 1 else 1000 end))
FROM q_locations
WHERE standalone = NEW.standalone);
END;
Update: So with help I got, I managed to insert trigger without no errors, bu when I update my locations table, trigger doesn't do anything. Values just keep incrementing as default.
Try:
SET NEW.id = (SELECT coalesce(...) ...)
Maybe SELECT INTO isn't working properly in Update Triggers with NEW-Aliases.
UPDATE:
This should work:
DELIMITER $$
CREATE TRIGGER trigger_insert_q_locations
BEFORE INSERT ON q_locations
FOR EACH ROW
BEGIN
DECLARE currentid INT;
SET currentid = (SELECT max(id) FROM q_locations WHERE standalone = NEW.standalone);
IF NEW.standalone = 0 THEN
SET NEW.id = coalesce(currentid + 1, 1);
ELSE
SET NEW.id = coalesce(currentid + 1,1000);
END IF;
END;

How to generate sequence in MySQL 5.1community edition

Can somebody please show me how generate a sequence in MySQL 5.1?
create table users
(
user_id int unsigned not null auto_increment primary key,
username varbinary(32) unique not null
...
)
engine=innodb;
you could also do
drop table if exists users_seq;
create table users_seq
(
next_val int unsigned not null default 0
)
engine = innodb;
insert into users_seq values (0);
drop table if exists users;
create table users
(
user_id int unsigned not null primary key,
username varbinary(32) unique not null
)
engine=innodb;
delimiter #
create trigger users_before_ins_trig before insert on users
for each row
begin
declare v_id int unsigned default 0;
select next_val+1 into v_id from users_seq;
set new.user_id = v_id;
update users_seq set next_val = v_id;
end#
delimiter ;
insert into users (username) values ('f00'),('foo'),('bar');
select * from users;
select next_val from users_seq;
MySQL doesn't have sequences, however it does have the auto-increment feature.
http://www.experts123.com/q/does-mysql-5.1-have-sequences.html
CREATE TABLE test (
customer_id bigint(21) NOT NULL PRIMARY KEY AUTO_INCREMENT
);