web-dev-qa-db-fra.com

Boucle à travers des valeurs séparées par des virgules

J'ai un Master DB. Je veux créer une base de données en double de la base de données principale, mais pas toutes les tables spécifiées.

J'ai ces noms de table dans une chaîne séparée par des virgules. tbl1, tbl2, tbl7, tbl10 etc.

J'essaie de faire passer une procédure stockée new DB name Cela crée la base de données et réplique la table donnée. Jusqu'à présent, j'ai 2 choses, mais je ne sais pas comment les parcourir. Je suis nouveau sur DB, veuillez guider comment y parvenir.

(Remarque) Je n'ai pas trouvé si un tableau peut être utilisé pour boucler, les noms de table peuvent également être stockés dans une variable de tableau, car les noms de table sont codé en dur.

Ce qui suit est le code Sudo que je désire.

CREATE DATABASE %param_db%;

@tables = 'tbl1, tbl2, tbl7, tbl10';
loop through @tables as table_name
    CREATE TABLE %param_db.table_name% LIKE Master.%table_name%;
End loop
5
Bsienn

Voici les étapes de mise en page dans la procédure stockée

  • Créer la base de données cible
  • Déterminer le nombre d'éléments dans la liste des tableaux
  • Parcourez chaque élément de la liste des tableaux en utilisant la fonction ELT ()
  • Prenez chaque élément et formez une instruction SQL pour créer la nouvelle table dans la base de données cible

Voici cette procédure stockée

DELIMITER $$

DROP PROCEDURE IF EXISTS `test`.`TableCookieCutter` $$
CREATE PROCEDURE `test`.`TableCookieCutter`
(
    SourceDB VARCHAR(64),
    TargetDB VARCHAR(64),
    TableList VARCHAR(1024)
)
BEGIN

    # Create the Target DB
    SET @sql = CONCAT('CREATE DATABASE IF NOT EXISTS ',TargetDB);
    PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

    # Strip Table List of Blanks
    # Enclose each table in quotes
    SET @table_list = CONCAT('''',REPLACE(REPLACE(TableList ,' ',''),',',QUOTE(',')),'''');

    # Count the number of tables in the list
    SET @table_stub = REPLACE(@table_list,',','');
    SET @array_count = LENGTH(@table_list) - LENGTH(@table_stub) + 1;

    # Loop through list of tables, creating each table
    SET @x = 0;
    WHILE @x < @array_count DO
        SET @x = @x + 1;
        SET @sql = CONCAT('SELECT ELT(',@x,',',@table_list,') INTO @tb');
        PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
        SET @sql = CONCAT('CREATE TABLE ',TargetDB,'.',@tb,' LIKE ',SourceDB,'.',@tb);
        PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
    END WHILE;

END $$

DELIMITER ;
7
RolandoMySQLDBA

@RolandoMySQLDBA le poste d'abord, mais j'ai une autre façon.

En utilisant ceci pour séparer la chaîne de virgule séparée et ceci pour le nombre d'occurrences , j'ai fait cette procédure stockée:

PROCÉDURE STOCKÉE:

CREATE DEFINER=`root`@`localhost` PROCEDURE `spCreateRplDB`(
IN iNewDB VARCHAR(100),
IN iOldDB VARCHAR(100),
IN iTables VARCHAR(150))
BEGIN
# Comma separated string
SET @repldb=iNewDB;
SET @masterdb=iOldDB;
SET @tbls=TRIM(iTables);
SET @counter=(SELECT ROUND((LENGTH(@tbls) - LENGTH( REPLACE (@tbls, ",", ""))) / LENGTH(",")));
SET @loop_num=0;
# Splitting comma separated string
IF (@counter>0 && @repldb<>'' && @masterdb <> '') THEN
    SET @counter=@counter+1; # [ ADDING +1 BECAUSE @counter JUST COUNT THE NUMBER OF OCCURENCES OF A STRING INSIDE @tbls ]
    # Creating DB if not exists
    SET @database_create=CONCAT(" CREATE DATABASE IF NOT EXISTS ",@repldb,";");
    PREPARE database_create FROM @database_create;
    EXECUTE database_create;
    DEALLOCATE PREPARE database_create;

    WHILE @loop_num<>@counter DO
        SET @loop_num=@loop_num+1; 
        SET @rownumber=0; # Row Number
        SET @tbl='';
        SELECT 
            v.value 
        INTO @tbl
        FROM (SELECT 
                    TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(t.value, ',', n.n), ',', -1)) AS value,
                    @rownumber:=@rownumber+1 AS rownumber
                FROM (SELECT @tbls AS value) AS t 
                CROSS JOIN (SELECT a.N + b.N * 10 + 1 n
                            FROM 
                            (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
                           ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
                                ORDER BY n
                            ) n
                WHERE n.n <= 1 + (LENGTH(t.value) - LENGTH(REPLACE(t.value, ',', ''))) 
                HAVING rownumber=@loop_num) AS v;
        # Creating Table
        SET @drop_table=CONCAT(" DROP TABLE IF EXISTS ",@repldb,".",@tbl,";");
        SET @create_table=CONCAT(" CREATE TABLE ",@repldb,".",@tbl," LIKE ",@masterdb,".",@tbl,";");
        # Preparing STMT for @drop_table
        PREPARE droptable FROM @drop_table;
        EXECUTE droptable;
        DEALLOCATE PREPARE droptable;
        # Preparing STMT for @create_table
        PREPARE create_table FROM @create_table;
        EXECUTE create_table;
        DEALLOCATE PREPARE create_table;
    END WHILE;
END IF;
END

PROCESSUS:

  1. @counter, nombre d'occurrences de , ( délimiteur de tables ).
  2. S'il y a plus de 0 occurrences et que iNewDB et iOldDB n'est pas nul ou vide, continuez.
  3. Créez la nouvelle base de données ( iNewDB ).
  4. Création de nouvelles tables avec le nombre d'entrées dans le paramètre iTables.

TESTER:

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| test_old           |
+--------------------+
5 rows in set (0.00 sec)

mysql> SHOW TABLES IN test_old;
+--------------------+
| Tables_in_test_old |
+--------------------+
| test1              |
| test2              |
| test3              |
| test4              |
+--------------------+
4 rows in set (0.00 sec)

mysql> 
mysql> CALL test.spCreateRplDB(
    -> 'test_dev', # New DB
    -> 'test_old', # Master DB
    -> 'test1,test2,test4');
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| test_dev           |
| test_old           |
+--------------------+
6 rows in set (0.00 sec)

mysql> SHOW TABLES IN test_dev;
+--------------------+
| Tables_in_test_dev |
+--------------------+
| test1              |
| test2              |
| test4              |
+--------------------+
3 rows in set (0.00 sec)

mysql> 
2
oNare