DELIMITER $$ CREATE PROCEDURE archive_last_days_dynamic( IN p_source_table VARCHAR(64), IN p_archive_table VARCHAR(64), IN p_date_column VARCHAR(64), IN p_days_back INT, IN p_batch_size INT ) BEGIN DECLARE done INT DEFAULT FALSE; DECLARE rows_affected INT DEFAULT 0; DECLARE total_rows INT DEFAULT 0; DECLARE insert_sql VARCHAR(4000); DECLARE delete_sql VARCHAR(4000); -- Validation IF p_source_table IS NULL OR p_source_table = '' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Source table name is required'; END IF; IF p_archive_table IS NULL OR p_archive_table = '' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Archive table name is required'; END IF; IF p_date_column IS NULL OR p_date_column = '' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Date column name is required'; END IF; IF p_days_back IS NULL OR p_days_back <= 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Days back must be greater than 0'; END IF; -- If batch size is NULL or <= 0, run once without LIMIT IF p_batch_size IS NULL OR p_batch_size <= 0 THEN SET insert_sql = CONCAT( 'INSERT INTO `', p_archive_table, '` ', 'SELECT * FROM `', p_source_table, '` ', 'WHERE `', p_date_column, '` <= NOW() - INTERVAL ', p_days_back, ' DAY' ); SET delete_sql = CONCAT( 'DELETE FROM `', p_source_table, '` ', 'WHERE `', p_date_column, '` <= NOW() - INTERVAL ', p_days_back, ' DAY' ); START TRANSACTION; SET @insert_sql = insert_sql; PREPARE stmt_insert FROM @insert_sql; EXECUTE stmt_insert; SET rows_affected = ROW_COUNT(); SET total_rows = rows_affected; DEALLOCATE PREPARE stmt_insert; SET @delete_sql = delete_sql; PREPARE stmt_delete FROM @delete_sql; EXECUTE stmt_delete; DEALLOCATE PREPARE stmt_delete; COMMIT; ELSE REPEAT SET insert_sql = CONCAT( 'INSERT INTO `', p_archive_table, '` ', 'SELECT * FROM `', p_source_table, '` ', 'WHERE `', p_date_column, '` <= NOW() - INTERVAL ', p_days_back, ' DAY ', 'LIMIT ', p_batch_size ); SET delete_sql = CONCAT( 'DELETE FROM `', p_source_table, '` ', 'WHERE `', p_date_column, '` <= NOW() - INTERVAL ', p_days_back, ' DAY ', 'LIMIT ', p_batch_size ); START TRANSACTION; SET @insert_sql = insert_sql; PREPARE stmt_insert FROM @insert_sql; EXECUTE stmt_insert; SET rows_affected = ROW_COUNT(); SET total_rows = total_rows + rows_affected; DEALLOCATE PREPARE stmt_insert; IF rows_affected > 0 THEN SET @delete_sql = delete_sql; PREPARE stmt_delete FROM @delete_sql; EXECUTE stmt_delete; DEALLOCATE PREPARE stmt_delete; END IF; COMMIT; IF rows_affected < p_batch_size THEN SET done = TRUE; END IF; UNTIL done END REPEAT; END IF; SELECT 'ok' AS status, total_rows AS total_rows_moved; END $$ DELIMITER ; //USE CALL archive_last_days_dynamic('source_table', 'archive_table', 'created_at', 30, 500);