This describes an update script for transforming table "ac_zones" by re-numbering 'zone_id' in intervals of 1000 entries per countries. Changes are reported in all other tables.
A trigger is created which calculates 'zone_id' based on 'country_id' at insertion.
Keeps the possibility to insert directly at a given 'zone_id'.
The auto_increment on table doesnt need to be removed.
ALTER TABLE ac_zones
ADD COLUMN new_zid
int(11) NOT NULL;
ALTER TABLE ac_zones
ADD COLUMN old_zid
int(11) NOT NULL;
UPDATE ac_zones
SET old_zid = zone_id;
SET @row_num := 0;
SET @prev_value := 0;
UPDATE ac_zones
t, (SELECT zone_id
, country_id
* 1000 + @row_num := IF (@prev_value = country_id
, @row_num + 1, 0) AS RowNumber, @prev_value := country_id
FROM ac_zones
ORDER BY country_id
,zone_id
ASC) r
SET t.new_zid = r.RowNumber
WHERE t.zone_id
= r.zone_id
;
DELIMITER $$
DROP PROCEDURE IF EXISTS modify_zid $$
CREATE PROCEDURE modify_zid()
BEGIN
DECLARE found INT DEFAULT TRUE;
DECLARE cur_table_name CHAR(255);
DECLARE cur_column_name CHAR(255);
DECLARE curs_zid CURSOR FOR
SELECT DISTINCT table_name, column_name FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name != 'ac_zones' AND column_name LIKE '%zone_id%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET found = FALSE;
OPEN curs_zid;
FETCH curs_zid INTO cur_table_name, cur_column_name;
WHILE (found) DO
SET @Sql = CONCAT('UPDATE ', cur_table_name, '
r SET r.', cur_column_name, ' = - (SELECT new_zid
FROM ac_zones
t WHERE t.old_zid = r.', cur_column_name,') WHERE r.', cur_column_name, ' IS NOT NULL AND r.', cur_column_name, ' != 0');
PREPARE stmt FROM @Sql;
EXECUTE stmt;
DROP PREPARE stmt;
SET @sql = CONCAT('UPDATE `', cur_table_name,
'` r SET r.', cur_column_name, ' = - r.', cur_column_name,
' WHERE r.', cur_column_name, ' IS NOT NULL AND r.', cur_column_name, ' < 0');
PREPARE stmt FROM @Sql;
EXECUTE stmt;
DROP PREPARE stmt;
FETCH curs_zid INTO cur_table_name, cur_column_name;
END WHILE;
CLOSE curs_zid;
END $$
CREATE TRIGGER trg_bi_zones BEFORE INSERT ON ac_zones
FOR EACH ROW
BEGIN
IF (NEW.zone_id = 0 OR NEW.zone_id IS NULL) THEN
SET NEW.zone_id = (SELECT IFNULL(MAX(zone_id) + 1, NEW.country_id * 1000) FROM ac_zones
WHERE zone_id >= (NEW.country_id * 1000) AND zone_id < ((NEW.country_id + 1) * 1000));
END IF;
END $$
DELIMITER ;
CALL modify_zid();
DROP PROCEDURE IF EXISTS modify_zid;
UPDATE ac_zones
SET zone_id = - new_zid;
UPDATE ac_zones
SET zone_id = - zone_id;
ALTER TABLE ac_zones
DROP COLUMN new_zid
;
ALTER TABLE ac_zones
DROP COLUMN old_zid
;