避免MySQL脚本中重复的语句

时间:2013-06-15 00:36:18

标签: mysql

我使用MySQL中的事件调度程序创建了一个自动备份,如下所示:

DELIMITER $$
CREATE DEFINER=`root`@`localhost` EVENT `Backup` 
ON SCHEDULE EVERY 1 WEEK 
STARTS '2013-06-14 18:19:02' ON COMPLETION NOT PRESERVE ENABLE 
DO 
BEGIN
SET @sql_text1 = CONCAT("SELECT * FROM BonInterne INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "BonInterne.csv'" ); 
SET @sql_text2 = CONCAT("SELECT * FROM LigneBonInterne INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "LigneBonInterne.csv'" ); 
SET @sql_text3 = CONCAT("SELECT * FROM BonExterne INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "BonExterne.csv'" ); 
SET @sql_text4 = CONCAT("SELECT * FROM LigneBonExterne INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "LigneBonExterne.csv'" ); 
SET @sql_text5 = CONCAT("SELECT * FROM BonEntrée INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "BonEntrée.csv'" ); 
SET @sql_text6 = CONCAT("SELECT * FROM LigneBonEntrée INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "LigneBonEntrée.csv'" ); 
SET @sql_text7 = CONCAT("SELECT * FROM Inventaire INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "Inventaire.csv'" ); 
SET @sql_text8 = CONCAT("SELECT * FROM LigneInterventaire INTO OUTFILE '/home/aimad/GestionStock/" , DATE_FORMAT( NOW(), '%Y%m%d') , "LigneInventaire.csv'" ); 
PREPARE s1 FROM @sql_text;
PREPARE s2 FROM @sql_text;
PREPARE s3 FROM @sql_text;
PREPARE s4 FROM @sql_text;
PREPARE s5 FROM @sql_text;
PREPARE s6 FROM @sql_text;
PREPARE s7 FROM @sql_text;
PREPARE s8 FROM @sql_text;
EXECUTE s1;
EXECUTE s2; 
EXECUTE s3; 
EXECUTE s4; 
EXECUTE s5; 
EXECUTE s6; 
EXECUTE s7; 
EXECUTE s8;  
DEALLOCATE PREPARE s1;
DEALLOCATE PREPARE s2;
DEALLOCATE PREPARE s3;
DEALLOCATE PREPARE s4;
DEALLOCATE PREPARE s5;
DEALLOCATE PREPARE s6;
DEALLOCATE PREPARE s7;
DEALLOCATE PREPARE s8;
END $$
DELIMITER ;

问题是有很多事情重复,例如DATE_FORMAT( NOW(), '%Y%m%d')以及执行语句和释放语句......

我的问题是,是否有其他方法可以用更少的行创建这个脚本?

2 个答案:

答案 0 :(得分:2)

你有很多重复的代码。在这种情况下(使用任何语言),您需要refactor您的代码。

将重复的部分提取到一个单独的过程中,传递任何必要的参数,并重新编写主程序以(重新)使用提取的代码。

DELIMITER $$

CREATE PROCEDURE DO_BACKUP(table_name text)
BEGIN
  SET @sql = CONCAT("SELECT * FROM ", table_name,
    " INTO OUTFILE '/home/aimad/GestionStock/" ,
    DATE_FORMAT( NOW(), '%Y%m%d') , table_name, ".csv'" );
  PREPARE s1 FROM @sql;
  EXECUTE s1;  
  DEALLOCATE PREPARE s1;
END$$

CREATE DEFINER=`root`@`localhost` EVENT `Backup` 
ON SCHEDULE EVERY 1 WEEK 
STARTS '2013-06-14 18:19:02' ON COMPLETION NOT PRESERVE ENABLE 
DO 
BEGIN
  CALL DO_BACKUP('BonInterne');
  CALL DO_BACKUP('LigneBonInterne');
  CALL DO_BACKUP('BonExterne');
  CALL DO_BACKUP('LigneBonExterne');
  CALL DO_BACKUP('BonEntrée');
  CALL DO_BACKUP('LigneBonEntrée');
  CALL DO_BACKUP('Inventaire');
  CALL DO_BACKUP('LigneInterventaire');
END $$

DELIMITER ;

它还可以使您的代码更易于阅读和维护。看看添加另一个表是多么容易。

一旦像这样重构,您可以通过存储在表格中的值轻松地驱动它。特别是如果您将过程更改为函数:

CREATE FUNCTION DO_BACKUP(table_name text)
RETURNS text
BEGIN
  -- as above
  RETURN NULL;
END$$

然后创建并填充一个表(一次):

CREATE TABLE backup_table (
  table_name text);

INSERT INTO backup_table values ('BonInterne'), ('LigneBonInterne'), etc;

然后你可以这样做:

select do_backup(table_name)
from table_name;

从备份中添加和删除表就像从表中插入和删除行一样简单。

答案 1 :(得分:1)

这就是你能做的。

首先让我们创建一个辅助函数,给定一个索引将返回一个表名

CREATE FUNCTION tname_from_idx(INT idx)
RETURNS VARCHAR(64)
RETURN CASE idx 
         WHEN 1 THEN 'BonInterne'
         WHEN 2 THEN 'LigneBonInterne'
         WHEN 3 THEN 'BonExterne'
         WHEN 4 THEN 'LigneBonExterne'
         WHEN 5 THEN 'BonEntrée'
         WHEN 6 THEN 'LigneBonEntrée'
         WHEN 7 THEN 'Inventaire'
         WHEN 8 THEN 'LigneInterventaire'
         ELSE 'n/a'
       END;

其次让我们将备份代码包装到存储过程中,这样每次我们想要更改备份逻辑时都不会更改事件

DELIMITER $$
CREATE PROCEDURE do_backup()
BEGIN
    DECLARE i     INT         DEFAULT 1;
    DECLARE tname VARCHAR(64) DEFAULT 'n/a';

    SET tname = tname_from_idx(i);
    WHILE  tname <> 'n/a' DO
      SET @sql = CONCAT('SELECT * FROM ', tname, ' INTO OUTFILE \'/home/aimad/GestionStock/', DATE_FORMAT(CURDATE(), '%Y%m%d'), tname, '.csv\'');
      PREPARE stmt FROM @sql; 
      EXECUTE stmt;
      DEALLOCATE PREPARE stmt;
      SET i = i + 1;
      SET tname = tname_from_idx(i);
    END WHILE;
END$$
DELIMITER ;

就是这样。现在,您只需从事件中调用此存储过程。

CREATE DEFINER=`root`@`localhost` EVENT `Backup` 
ON SCHEDULE EVERY 1 WEEK STARTS CURDATE() + INTERVAL 22 HOUR 
DO CALL do_backup();

注意:我们的函数和事件是一个语句。因此,他们不需要使用DELIMITERBEGIN ... END