IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Split de fichiers SQL multi-requêtes [RegEx]


Sujet :

Langage PHP

  1. #1
    Membre régulier
    Homme Profil pro
    Etudiant CNAM (DIE20)
    Inscrit en
    Janvier 2010
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant CNAM (DIE20)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 151
    Points : 97
    Points
    97
    Par défaut Split de fichiers SQL multi-requêtes
    Bonjour,

    Je n'arrive pas à trouver comment faire une regex qui trouve les point-virgules pour séparer des requêtes SQL, sachant qu'il peut y avoir des fonctions (qui contiennent donc des points virgules dans leur corps);

    Par exemple, avec un preg_replace(), je souhaite convertir :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DROP FUNCTION IF EXISTS maFonction (INTEGER,INTEGER,TIMESTAMP);
    CREATE FUNCTION maFonction (INTEGER,INTEGER,TIMESTAMP)
    	RETURNS INTEGER
    AS $$
    DECLARE
    	id INTEGER;
    BEGIN
    	blabla;
    	IF id IS NULL THEN
    		blabla;
    	END IF;
    	RETURN id;
    END;
    $$ LANGUAGE PLPGSQL;

    en :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DROP FUNCTION IF EXISTS maFonction (INTEGER,INTEGER,TIMESTAMP);###
    CREATE FUNCTION maFonction (INTEGER,INTEGER,TIMESTAMP)
    	RETURNS INTEGER
    AS $$
    DECLARE
    	id INTEGER;
    BEGIN
    	blabla;
    	IF id IS NULL THEN
    		blabla;
    	END IF;
    	RETURN id;
    END;
    $$ LANGUAGE PLPGSQL;###

    La difficulté est donc de ne pas tenir compte des point-virgules entre "CREATE FUNCTION" ET "PLPGSQL" par exemple.

    Après, il me suffit de faire un explode sur '###' pour mettre chaque requête séparément dans un tableau.
    (EDIT : ou preg_split(), et rajout du point-virgule en fin de chaque chaine)

    J'ai regardé du côté des assertions avant/arrières, mais je n'ai pas réussi à mettre en œuvre quelque chose qui fonctionne...

    Merci d'avance pour l'aide apportée.

  2. #2
    Membre régulier
    Homme Profil pro
    Etudiant CNAM (DIE20)
    Inscrit en
    Janvier 2010
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant CNAM (DIE20)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 151
    Points : 97
    Points
    97
    Par défaut
    J'ai trouvé cette solution qui fonctionne, mais passe par des étapes intermédiaires :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    // chaine à traiter
    $chaine = "DROP FUNCTION IF EXISTS maFonction (INTEGER,INTEGER,TIMESTAMP);
    CREATE FUNCTION maFonction (INTEGER,INTEGER,TIMESTAMP)
    	RETURNS INTEGER
    AS $$
    DECLARE
    	id INTEGER;
    BEGIN
    	blabla;
    	IF id IS NULL THEN
    		blabla $1;
    	END IF;
    	RETURN id;
    END;
    $$ LANGUAGE PLPGSQL;
     
    DROP FUNCTION IF EXISTS maFonction (INTEGER,INTEGER,TIMESTAMP);
    CREATE FUNCTION maFonction (INTEGER,INTEGER,TIMESTAMP)
    	RETURNS INTEGER
    AS $$
    DECLARE
    	id INTEGER;
    BEGIN
    	blabla;
    	IF id IS NULL THEN
    		blabla $1;
    	END IF;
    	RETURN id;
    END;
    $$ LANGUAGE PLPGSQL;";
     
    // motif détectant le corps d'une fonction plpgsql
    $pattern = "#create\sfunction(.*)plpgsql#siU";
     
    // fonction remplaçant les point virgules (destinée à traiter le corps de la fonction)
    function remplacePointsVirgules($arg) {
        return str_replace(';', '###', $arg[0]);
    }
     
    // traitement du corps de la fonction pour remplacer ses points-vigules
    $tmp = preg_replace_callback($pattern, "remplacePointsVirgules", $chaine);
     
    // explode sur les points-virgules restants (en dehors des corps de fonction
    $tmp = explode(';', $tmp);
     
    // traitement du tableau obtenu avec rétablissement des points-virgules des corps de fonction et en fin de commande SQL
    foreach ($tmp as $sql) {
        $sql = trim($sql);
        if (strlen($sql))
            $tableauSQL[] = str_replace('###', ';', $sql).';';
    }
    var_dump($tableauSQL);

    Je suis preneur d'une solution plus simple / plus élégante !

  3. #3
    Membre régulier
    Homme Profil pro
    Etudiant CNAM (DIE20)
    Inscrit en
    Janvier 2010
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant CNAM (DIE20)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 151
    Points : 97
    Points
    97
    Par défaut
    Bonjour,

    Je bosse à nouveau sur mon projet de juin et je reviens à la charge pour une solution "full regex".

    Je sais comment sélectionner la partie à ne pas modifier :
    @(BEGIN.*;.*END;)@gsUi

    Je sais comment repérer les ';' :
    @(;)@g

    Mais comment faire pour sélectionner les ';' qui ne sont pas contenus dans les matchs de la 1ère regex ???

    NB : ma fonction actuelle qui fait ce travail :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    /* Lit un fichier contenant des commandes SQL,
     * supprime les liens vides et les commentaires,
     * et renvoie un tableau des commandes trouvées
     * TODO : pb si ";" au sein d'une chaine
     */
    public static function extract_SQL_commands ($nomFichierSQL) {
     
        // Récupération des données
        $rows_SQL = file($nomFichierSQL);
     
        // Suppression de l'éventuel BOM_UTF8
        $rows_SQL[0] = ltrim($rows_SQL[0],"\xEF\xBB\xBF");
     
        // Suppression des commentaires et génération d'une string unique
        $string_SQL = "";
        foreach ($rows_SQL as $row) {
            $row = rtrim(explode("--",$row)[0]);
            $row = rtrim($row);
            if (strlen($row)>0) {
                $string_SQL .= "$row\r\n";
            }
        } unset($row);
     
        // Protéger des points-vigules situés au sein de fonctions
        $string_SQL = preg_replace_callback(
            // motif détectant le corps d'une fonction
            "#(BEGIN.*END\s*;)#sUi",
            // fonction remplaçant les point virgules (destinée à traiter le corps de la fonction)
            function ($matches) {
                return str_replace(';', '###', $matches[0]);
            },
            $string_SQL
        );
     
        // Explode sur les points-virgules restants (en dehors des corps de fonction)
        $array_SQL = explode(";",$string_SQL);
     
        // Rétablisement des point-virgules, et nettoyage commandes
        foreach ($array_SQL as &$command) {
            $command = str_replace('###', ';', $command);
            $command = ltrim($command).";";
        } unset ($command);
     
        // Suppression dernière commande vide
        $i = count($array_SQL)-1;
        if ($array_SQL[$i] == ';') unset ($array_SQL[$i]);
     
        return $array_SQL;
    }

  4. #4
    Membre habitué Avatar de denissay
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2006
    Messages : 103
    Points : 125
    Points
    125
    Par défaut
    Bonjour,

    En se basant sur ton premier post, tu peux tester le pattern suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /^(?:(CREATE FUNCTION.*?PLPGSQL;)|([^;]+;))/gms
    En gros, il fonctionne comme suit:
    • Si la ligne commence par "CREATE FUNCTION", ça veut dire que c'est une fonction, et donc il capture tous jusqu'à "PLPGSQL;"
    • Sinon, c'est une requete simple, et donc il capture tous jusqu'à la première ";"


    Voici une Demo

    À noter donc que le pattern capture les fonctions dans le groupe 1, et les requêtes simples dans le groupe 2.

    Finalement, fait attention aux drapeaux (flags):
    • g => Global: Pour tous récupérer, pas uniquement le premier match (peut être pas besoin, à toi de vérifier la doc de la fonction utilisée)
    • m => Multi-line: Il traitechaque ligne séparément
    • s => Single line: le "." correspondra au retour chariot "\n"

    Plus de détails peuvent être trouvés ICI
    Une réponse utile vous a aidé ? N'oubliez pas le
    Votre problème est résolu ? N'oubliez pas le

  5. #5
    Membre régulier
    Homme Profil pro
    Etudiant CNAM (DIE20)
    Inscrit en
    Janvier 2010
    Messages
    151
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant CNAM (DIE20)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 151
    Points : 97
    Points
    97
    Par défaut
    Super !

    Un grand merci. Je viens de passer une heure dessus mais je crois avoir finalement bien compris le principe.

    J'ai adapté à mes besoins comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /^\s*(?:(CREATE (?:[^;]*)?FUNCTION.*?PLPGSQL[']?;)|([^;]+;))/gmsi
    DEMO

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Requête SQL multi schémas
    Par Monfy29 dans le forum SQL
    Réponses: 4
    Dernier message: 15/08/2008, 13h06
  2. [SQL] Créer Requête Multi-Critères
    Par ArHacKnIdE dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 11/04/2008, 14h13
  3. [Debutant] Requête SQL Multi-Tables
    Par Superbretzel dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 16/02/2008, 11h47
  4. [ADO] Exécuter des requêtes contenues dans un fichier SQL
    Par Lucas Panny dans le forum Visual C++
    Réponses: 1
    Dernier message: 29/01/2008, 06h35
  5. Postgres : requête à partir d'un fichier .sql
    Par odyssee2 dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 12/08/2005, 12h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo