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

Requêtes MySQL Discussion :

[MySQL - PhP - Propel] Génération de requêtes personnalisés


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Par défaut [MySQL - PhP - Propel] Génération de requêtes personnalisés
    Bonjour,

    Je me trouve confronté à un problème assez "conséquent". Je m'explique.

    Technologies utilisées : Php, Symfony 1.0, MySQL, Propel

    Les utilisateurs doivent pouvoir via une interface, générer automatiquement des requêtes personnalisées sur la base de donnée et de renvoyer un CSV avec les informations demandées via checkbox.


    Exemple : Extraction personnalisée sur Individu

    Doit me renvoyer une requête du genre
    Civilite = Mme AND (Pays = France OR Pays = BELGIQUE)

    Pour l'instant, je générais des requêtes via les criterias de Propel en regardant l'opérateur à n-1 pour ajouter un criteria addOr au lieu de addAnd.

    Le problème c'est que pour cet exemple il me sort alors :
    (Civilite = Mme AND Pays = France) OR Pays = BELGIQUE

    Ce qui fait que je me retrouve avec des Mr dans ma requête.

    On peut ajouter des critères de sélection via un bouton, ce qui rajoute une ligne avec un opérateur sur la ligne précédente.



    Les opérateurs proposés : ET, OU, SAUF


    Le problème c'est que je ne vois pas comment construire le schéma basique qui me permettrait de générer, par la suite, une requête personnalisée plus longue et plus complexe.
    Je dois prendre en compte tout les schémas possible et je n'arrive pas à créer une fonction qui permette que toutes mes requêtes soient correctement organisé en fonction de mes opérateurs (ET, OU, SAUF).


    Extrait de mon code de traitement :
    Code : 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
    53
    54
    55
    56
    57
     
    	foreach($types as $key => $type){
    		// Recherche de loperateur
    		$operateur = 'addAnd';
     
    		if ($key > 0 && $operateurs[$key-1] == 'OU') {
    			$operateur = 'addOr';
    		}
     
    		$crit = 'EQUAL';
     
    		if($key > 0 && $criterias[$key]!=''){
    			if ($operateurs[$key-1] == 'SAUF') {
    				$crit = 'NOT_EQUAL';
    			}
    		}else{
    			if ($key > 0 && $operateurs[$key-1] == 'SAUF') {
    				$crit = 'ISNOTNULL';
    			}else{
    				$crit = 'ISNULL';
    			}
    		}
     
     
     
    		switch ($type) {
    		//en fonction des types je génére des critérias exemple:
    		    case "adresse":
    		    case "nom":
    		    case "prenom":
    		          $typeContante = constant ('IndividuPeer::'.strtoupper ($type));
    		          if($key>0){
                                    if($criterias[$key]=='' && $operateurs[$key-1] == 'SAUF')
                                             $criterionTemp = $criteria->getNewCriterion ($typeContante, Criteria::ISNOTNULL);
                                    else if($criterias[$key]=='' && $operateurs[$key-1] != 'SAUF')
                                             $criterionTemp = $criteria->getNewCriterion ($typeContante, Criteria::ISNULL);
                                    else if($criterias[$key]!='' && $operateurs[$key-1] == 'SAUF')
                                          $criterionTemp = $criteria->getNewCriterion ($typeContante, '%'.$criterias[$key].'%', Criteria::NOT_LIKE);
                                    else
                                          $criterionTemp = $criteria->getNewCriterion ($typeContante, '%'.$criterias[$key].'%', Criteria::LIKE);
                           }else{
                                     if($criterias[$key]=='')
                                            $criterionTemp = $criteria->getNewCriterion ($typeContante, Criteria::ISNULL);
                                     else
                                            $criterionTemp = $criteria->getNewCriterion ($typeContante, '%'.$criterias[$key].'%', Criteria::LIKE);
                            }
                            if ($key == 0) 
                                $criteria->addAscendingOrderByColumn($typeContante);
    			    break;
                     }
     
                      if ($key > 0)
    			$criterion->$operateur($criterionTemp);
    		else{
                    	$criterion = $criterionTemp;
    		}
    }

  2. #2
    Membre émérite
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Par défaut
    Si j'étais toi, je ferai plutôt des critères de sélection "Colonne, opérateur, valeur", car tu ne vas pas aller loin avec tes OU,ET et SAUF.
    Avec comme choix d'opérateur =,!=, <,>,<=,>= , et même MIN,MAX (dans ce cas pas de valeur)

    Pour ton problème de "OU", à mon avis, le plus simple est de pouvoir ajouter un groupe de critère de sélection. Dans un groupe de critère tu ne fais que des ET et entre chaque groupe tu fais un OU.

    Par exemple, si tu veux faire :
    Civilite = Mme AND (Pays = France OR Pays = BELGIQUE)

    Tu fais un premier groupe :
    (
    Civilite = Mme
    AND
    Pays = France

    )
    Et un second :
    OR
    (
    Civilite = Mme
    AND
    Pays = BELGIQUE
    )


    Evidemment, si un utilisateur veux faire une requête avec des OU dans tous les sens, ça risque d'être laborieux!!!

  3. #3
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Par défaut
    Je comprends ton point de vue avec la sélection "Colonne, opérateur, valeur"

    Mais cela devra quand même avoir des opérateur de groupement après ... Pour lier les lignes les unes avec les autres.

    Sachant que je n'ai pas besoin des >, <, MIN, MAX.... Mes spécifications sont claires... J'ai juste besoin de == et !=. Donc ET et OU et SAUF sont suffisant.
    L'interface réalisée est conforme aux spécificités... Elle est simple d'utilisation et corresponds au besoin du client.

    Le problème reste de lister des "règles" pour lire une ligne de donnée afin de l'interprêter en propel ou en SQL.

    Exemple:
    Civilite = Mme AND (Pays = France OR Pays = BELGIQUE)

    SI op = ET
    * alors ???
    SI op = OU
    * alors ???
    SI op[n-1] = OU
    * alors ???

    etc...


    EXEMPLE issu du cahier des charges

    CIVILITE mme ET
    www toto.fr OU
    metier chanteur OU
    telephone 0102030405 ET
    ville LYON OU
    civilite aucune


    donne :
    C1 = Mme ET (C2 contient 'onda.fr' OU C3 = chanteur OU C4 contient '0102030405') ET (C5 contient 'LYON' OU C6 est vide)

  4. #4
    Membre émérite
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Par défaut
    Citation Envoyé par leya_jarhan Voir le message
    Je comprends ton point de vue avec la sélection "Colonne, opérateur, valeur"

    Mais cela devra quand même avoir des opérateur de groupement après ... Pour lier les lignes les unes avec les autres.
    ???
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM table WHERE a=1 AND (b=2 OR b=3)
    donnera exactement le même résultat que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM table WHERE (a=1 AND b=2) OR ( a=1 AND b=3)
    Citation Envoyé par leya_jarhan Voir le message
    Sachant que je n'ai pas besoin des >, <, MIN, MAX.... Mes spécifications sont claires... J'ai juste besoin de == et !=. Donc ET et OU et SAUF sont suffisant.
    Qui peut le plus peut le moins. Pas la peine de tous les implémenter tout de suite, mais si un jour on te les demandes, tu ne seras pas obligé de tout casser...

    Citation Envoyé par leya_jarhan Voir le message
    L'interface réalisée est conforme aux spécificités... Elle est simple d'utilisation et corresponds au besoin du client.
    Personnellement, je ne trouve pas ça trivial d'écrire :
    Civilite Mme ET
    Pays France SAUF
    Je préfère :
    Civilite = Mme
    Pays != France
    Citation Envoyé par leya_jarhan Voir le message
    Le problème reste de lister des "règles" pour lire une ligne de donnée afin de l'interprêter en propel ou en SQL.

    Exemple:
    Civilite = Mme AND (Pays = France OR Pays = BELGIQUE)

    SI op = ET
    * alors ???
    SI op = OU
    * alors ???
    SI op[n-1] = OU
    * alors ???

    etc...
    Si tu restes avec tes OU,ET et SAUF, effectivement ça risque d’être compliqué...
    Alors qu'avec la méthode que je t'ai proposé c'est assez simple de formater le "WHERE" d'une requête SQL:
    Code : 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
    $where="";
    foreach($group) {
     
      if($firstGroup) {
        $firstGroup=false;
      }
      else {
        $where+=" OR ";
      }
     
      $where+="(";  
     
      foreach($criteredugroup) {
     
        $where+=$criteredugroup->type;
     
        $where+=" ";
        if($criteredugroup->criterias=="") {
     
          if($criteredugroup->operateur=="=") {
             $where+= "IS NULL";
          }
          else if($criteredugroup->operateur=="!=") {
             $where+= "IS NOT NULL";
          }
          else {
            //TODO
          }
        }
        else {
          $where+=$criteredugroup->operateur;
          $where+=" ";
          $where+=$criteredugroup->criterias;   
        }
      }
      $where+=")";  
    }

  5. #5
    Membre émérite
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Par défaut
    Citation Envoyé par leya_jarhan Voir le message
    EXEMPLE issu du cahier des charges

    CIVILITE mme ET
    www toto.fr OU
    metier chanteur OU
    telephone 0102030405 ET
    ville LYON OU
    civilite aucune


    donne :
    C1 = Mme ET (C2 contient 'onda.fr' OU C3 = chanteur OU C4 contient '0102030405') ET (C5 contient 'LYON' OU C6 est vide)
    Tu as des "=" et des "contient" comment vas tu pouvoir faire la différence en n'utilisant que ET, OU et SAUF ?

    EDIT 1:
    Et effectivement, si il faut faire cette requête avec des groupes c'est pas terrible :
    C1 = Mme ET C2 contient 'onda.fr' ET C5 contient 'LYON'
    OU
    C1 = Mme ET C2 contient 'onda.fr' ET C6 est vide
    OU
    C1 = Mme ET C3 = chanteur ET C5 contient 'LYON'
    OU
    C1 = Mme ET C3 = chanteur ET C6 est vide
    OU
    C1 = Mme ET C4 contient '0102030405' ET C5 contient 'LYON'
    OU
    C1 = Mme ET C4 contient '0102030405' ET C6 est vide
    EDIT 2:
    Comment vas tu pouvoir faire ce genre de requête ?:
    (C1 = Mme ET C2 contient 'toto.fr') OU (C1 = Mr ET C2 contient 'titi.fr')

  6. #6
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Par défaut
    Citation Envoyé par Fred_34 Voir le message
    Tu as des "=" et des "contient" comment vas tu pouvoir faire la différence en n'utilisant que ET, OU et SAUF ?
    Ce qui va faire la différence ce sera si le champ dans lequel il rentre les données sont des input ou des select. Les input donneront un LIKE ou un NOT LIKE à la place du == ou !=.

    Citation Envoyé par Fred_34 Voir le message
    Comment vas tu pouvoir faire ce genre de requête ?:
    (C1 = Mme ET C2 contient 'toto.fr') OU (C1 = Mr ET C2 contient 'titi.fr')
    Tu prends le problème à l'envers... Les utilisateurs m'ont envoyé une spéc... Je ne fais que la suivre. Je ne peux leur proposer une interface différente de celle imposée car sinon cela va engendrer des coûts de notre côté.

    Je cherche une solution pour le problème qui m'est apporté à savoir : une interface qui se présente comme définie précédement, avec gestion des lignes "une par une" où le OU est prioritaire et s'applique seulement à la ligne où il est placé et la suivante.

    Reste à définir comment créer une liste de règles pour le codage et pour la lecture de ces lignes pour en générer une requête SQL.

  7. #7
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2010
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2010
    Messages : 17
    Par défaut
    Que pensez - vous de ce genre de proposition ? (valable pour ET et OU)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    for($i=0;$i<count($tab);$i++){
        IF $tab['operateur'][$i] == 'OU'{
               if( $ma_requete_where != ' '){
                      $ma_requete_where .= $tab['operateur'][$i-1];
               }
               $ma_requete_where .= ' ( '+$tab['champ'][$i]+' = '+$tab['valeur'][$i]+' OR
                                                 '$tab['champ'][$i+1]+' = '+$tab['valeur'][$i+1]+') ';
               $i++;
        }else{
             if( $ma_requete_where != ' '){
                     $ma_requete_where .= 'AND';
             }
             $ma_requete_where .= $tab['champ'][$i] + ' = ' + $tab['valeur'][$i];
    }

  8. #8
    Membre émérite
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Par défaut
    Citation Envoyé par leya_jarhan Voir le message
    Tu prends le problème à l'envers... Les utilisateurs m'ont envoyé une spéc... Je ne fais que la suivre. Je ne peux leur proposer une interface différente de celle imposée car sinon cela va engendrer des coûts de notre côté.
    Et dans ta spec, est-il expliqué comment tu dois gérer les SAUF ?

    Que doit donner :
    C1 Mme SAUF
    C3 chanteur SAUF
    Tu peux avoir ces deux résultats :
    C1 != Mme ET C3 !=chanteur
    C1 != Mme OU C3 !=chanteur

    Il faudrait donc ajouter "SAUF ET" et "SAUF OU"...

    Ce ne doit pas être très loin de la spec si tu ajoutes une colonne opérateur (avec uniquement = et !=) et que tu gardes ta colonne opérateur actuel mais avec uniquement le ET et le OU:
    "Colonne, opérateur ( = / !=), valeur , liaison ( ET / OU / Rien)"
    Ton "where" est alors assez simple à écrire :
    Code : 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
          $insideOR=false;
        $ma_requete_where='';
        FOR($i=0;$i<count($tab);$i++){
     
          IF $tab['operateur'][$i] == 'OU'{
            if(!$insideOR) {
              $ma_requete_where.= '(';
              $insideOR=true;
            }
            $ma_requete_where.= $tab['champ'][$i];
            $ma_requete_where.= $tab['newOperateur'][$i];
            $ma_requete_where.= $tab['valeur'][$i];
            $ma_requete_where.= " OR ";
          }
          ELSE IF $tab['operateur'][$i] == 'ET'{
            $ma_requete_where.= $tab['champ'][$i];
            $ma_requete_where.= $tab['newOperateur'][$i];
            $ma_requete_where.= $tab['valeur'][$i];
     
            if( $insideOR) {
              $ma_requete_where.=')';
              $insideOR=false;
            }
            $ma_requete_where.= " AND ";
          }
          else {// C'est forcement le dernier
            $ma_requete_where.= $tab['champ'][$i];
            $ma_requete_where.= $tab['newOperateur'][$i];
            $ma_requete_where.= $tab['valeur'][$i];
            if( $insideOR) {
              $ma_requete_where.=')';
              $insideOR=false;
            }
          }
        }
    Si tu remplaces "$tab['newOperateur'][$i]" par "'='" c'est plus ou moins ta proposition corrigée.

Discussions similaires

  1. [MySQL] Problème de requête imbriquée (mysql) & php
    Par niacinside dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 21/05/2008, 11h59
  2. Réponses: 3
    Dernier message: 16/08/2006, 17h05
  3. [Php/MySQL] Envoi de mails selon requête
    Par martonpylon12 dans le forum Débuter
    Réponses: 7
    Dernier message: 28/03/2006, 15h00
  4. Réponses: 14
    Dernier message: 17/03/2003, 19h31

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