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

PHP & Base de données Discussion :

Recherche sur plusieurs tables


Sujet :

PHP & Base de données

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 17
    Points : 12
    Points
    12
    Par défaut Recherche sur plusieurs tables
    Bonjour à tous,

    dans le cadre d'un moteur de recherche, je souhaite obtenir les résulats d'une requete sur plusieures tables, sur plusieures pages...

    je fais la recherche facilement avec plusieurs select seulement je ne vois pas comment l'afficher sur plusieures pages sans passer par des javascript ou des cookies.

    aussi j'aimerai utiliser le LIMIT de mysql pour afficher ces résultats sur plusieures pages.

    je précise que les tables sont identiques, seul le nom des tables et ce qu'elles contiennent diffèrent.

    voici ce que j'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select table1.champ1, table1.champ2, table2.champ1 , table2.champ2 from table1, table2 where (table1.champ1 REGEXP '[ \'.,:;!]".$recherche1."[ .,:;!]|^".$recherche1."[ .,:;!]|[ .,:;!]".$recherche1."$' or table1.champ2 REGEXP '[ \'.,:;!]".$recherche2."[ .,:;!]|^".$recherche2."[ .,:;!]|[ .,:;!]".$recherche2."$') or (table2.champ1 REGEXP '[ \'.,:;!]".$recherche1."[ .,:;!]|^".$recherche1."[ .,:;!]|[ .,:;!]".$recherche1."$' or table2.champ2 REGEXP '[ \'.,:;!]".$recherche2."[ .,:;!]|^".$recherche2."[ .,:;!]|[ .,:;!]".$recherche2."$') LIMIT 0,10
    $recherche1 et $recherche2 sont le resultat d'un split de $recherche

    Autre précision je travaille sur 20 tables et pour chacune 10 champs, les tests effectués non seulement ne renvoi pas les bons résultats mais en plus c'est très très long.

    Avez-vous d'autres solutions, je suis quand même pas le premier à le faire et je trouve rien dans google :

    Merci d'avance.

    hubidev

  2. #2
    Rédacteur

    Avatar de Yogui
    Homme Profil pro
    Directeur technique
    Inscrit en
    Février 2004
    Messages
    13 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Février 2004
    Messages : 13 721
    Points : 29 985
    Points
    29 985
    Par défaut
    Salut

    Pourrais-tu, je te prie, utiliser la balise [code] pour copier du code ? Cela devient très rapidement illisible si on ne le fait pas :/

    Sinon, j'ai l'impression que tu ne fais pas de jointure sur tes tables. Tu te contentes de sélectionner sur plusieurs tables, ce qui donne un produit cartésien des résultats de chaque table.
    Je te recommande cet article pour t'aider à améliorer ta requête (et ainsi réduire son temps d'exécution) :
    http://sql.developpez.com/sqlaz/jointures/

    Concernant ton problème de pagination, tu peux faire une recherche sur Développez.com car le sujet a déjà été traité à plusieurs reprises.
    Exemple : http://www.developpez.net/forums/vie...591852#2591852

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    merci pour ta réponse

    voilà j'ai modifié mon message avec la balise code

    si j'ai bien compris je fais ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select table1.champ1, table1.champ2, table2.champ1 , table2.champ2 from table1, table2 where table1.champ1=table2.champ1 and table1.champ2=table2.champ2 and (MATCH (table1.champ1,table1.champ2) AGAINST ('$recherche1') and MATCH (table1.champ1,table1.champ2) AGAINST ('$recherche2')) or (MATCH (table2.champ1,table2.champ2) AGAINST ('$recherche1') and MATCH (table2.champ1,table2.champ2) AGAINST ('$recherche2')) LIMIT 0,10
    et ça devrai me sortir les résultats des deux tables ?
    avec 20 tables, 10 champs, et des requetes à 6 mots ça fait beaucoup non?

    avant d'essayer de tout faire en un seul select je bouclais sur un select pour chacune des tables (je vais tester aussi la pagination avec plusieurs select que tu m'as indiqué)
    je me demande quel sera la solution la plus rapide?

    hubidev

  4. #4
    Rédacteur

    Avatar de Yogui
    Homme Profil pro
    Directeur technique
    Inscrit en
    Février 2004
    Messages
    13 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Février 2004
    Messages : 13 721
    Points : 29 985
    Points
    29 985
    Par défaut
    Salut

    Non, je parlais de jointures, c'est-à-dire mettre des "table1.id=table2.id" ou bien des INNER JOIN.
    L'autre solution, si les jointures ne peuvent pas être appliquées dans ton cas (ce que je soupçonne), serait d'utiliser UNION. Tu pourrais ainsi écrire une requête pour une seule table et la répéter pour chacune de tes tables en mettant UNION. Cela te donnerait une seule requête et des résultats combinés.

    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT champ1, champ2
    FROM table1
    MATCH (champ1, champ2) AGAINST ('$recherche1')
       AND MATCH (champ1, champ2) AGAINST ('$recherche2')
    LIMIT 0, 10
    UNION
    SELECT champ1, champ2
    FROM table2
    MATCH (champ1, champ2) AGAINST ('$recherche1')
       AND MATCH (champ1, champ2) AGAINST ('$recherche2')
    LIMIT 0, 10
    Bien entendu, tu peux dynamiser tout ça...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $recherche1 = 'azerty';
    $recherche2 = 'qwerty';
     
    $tables = array('table1', 'table2', 'table3'); // Ici, tu ajoutes ou enlèves les tables dans lesquelles tu veux faire ta recherche
    $selects = array();
    foreach($tables as $table){
       $selects[] = "SELECT champ1, champ2
                   FROM ".$table."
                   MATCH (champ1, champ2) AGAINST ('".$recherche1."')
                      AND MATCH (champ1, champ2) AGAINST ('".$recherche2."')
                   LIMIT 0, 10";
    }
     
    $sql = implode(' UNION ', $selects);
    N.B. : Je n'ai pas testé, je ne sais pas vraiment si cela pourrait marcher.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 17
    Points : 12
    Points
    12
    Par défaut
    c'est bien ce qui me semblait JOIN c'est pas pour moi. Vu que c'est des tables qui représentent différentes catégories et qui n'ont pas de correspondance entre elles.

    Par contre UNION est un élément MySQL que je ne connaissais pas, merci de me l'avoir indiquer c'est exactement ce qu'il me fallait. (heu je n'ai pas lu la bible MySQL )

    voici le résultat

    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
    58
    59
    60
    61
     
    function cherche($cat,$recherches,$andor) {
    include("config/connectdb.php");
    $sel=1;
    $nbr=1;
    $etoile="champ1, champ2, champ3, champ4, champ5";
    	foreach($cat as $table){ 	
       	${"selects".$sel} = "SELECT ".$etoile." FROM ".$table." WHERE ";
    			foreach($recherches as $cherh){ 	
    				if ($nbr==1) {
    		   		${"selects".$sel}.="MATCH (".$etoile.") AGAINST ('+".$cherch."' IN BOOLEAN MODE) ";
    		   		} else {
    		   		${"selects".$sel}.=$andor." MATCH (".$etoile.") AGAINST ('+".$cherch}."' IN BOOLEAN MODE) ";
    		   		}
    				$nbr++;
    		   	}
    		   	if ($sel==1) {
    		   	$sql.=${"selects".$sel};
    		   	} else {
    		   	$sql.=" UNION ".${"selects".$sel};
    		   	}
        		$sel++;
    	}
    	$sql.=" and valid='1' ORDER by champ1 LIMIT 0, 10";
    	$r=mysql_db_query($database,$sql);
    	$n=mysql_num_rows($r);	
    			if ($n != 0) {
    				while ($i<$n)
    				{
    				echo stripslashes(mysql_result($r,$i,"champ1"));
    				}
    				return true;
    			} else {
    			return false;
    			}
    } 
     
    // -------- appel de la fonction  ---------
     
    $chercher="recherche un mot dans plusieures tables";
    //ici je traite cette chaine pour obtenir des mots distincts et j'obtient donc :
    $cherchmot[1]="recherche";
    $cherchmot[2]="mot";
    $cherchmot[3]="plusieures";
    $cherchmot[4]="tables";
    $no=count($cherchmot); //nombre de mots
     
    	//je selectionne les tables
    	$rq="SELECT nomtables FROM 'tableadmmin' WHERE valid = 1";
        mysql_db_query($database,$rq);
    	$result= mysql_query ($rq);
       	while ($dt=mysql_fetch_row($result)) {
    		$catini[$i]=$dt[0];
    		$i=$i+1;		
    	}
     
    	//j'appele la fonction une à deux fois
    	if (cherche($catini,$cherchmot,'and')==true) {
    	} else if (cherche($catini,$cherchmot,'and')==false and $no>1) { //si pas de résultat et si il ya plus d'un mot, je met un OR 
    	cherche($catini,$cherchmot,'or');
    	}
    ça marche très bien dans tous les cas qui me concerne

    plusieures questions:

    1. j'aurai préféré utiliser un tableau selects[] comme tu m'avais indiqué et faire $sql = implode(' UNION ', $selects); mais je ne sais pas comment ajouter des éléments: select[].="blabla"; ne marche pas, ça me génère un nouvelle entrée au tableau selects[]


    2. lorsque j'essaye :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT ".$etoile." FROM ".$table." WHERE MATCH (".$etoile.") AGAINST ('".$cherch."')";
    donc sans le 'IN BOOLEAN MODE'
    j'obtient :
    MySQL a répondu:
    #1191 - Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes
    alors que j'ai bien du fulltext pour les colonnes concernées:
    [...]
    PRIMARY KEY (`id`),
    FULLTEXT KEY `champ1` (`champ1`),
    [...]
    ) TYPE=MyISAM AUTO_INCREMENT=1 ;
    et avec 'IN BOOLEAN MODE' j'obtient des résultats même sur les tables que je n'ai rien changé avec :
    ALTER TABLE `table1` ADD FULLTEXT ( `champ1`)
    Je ne vois pas d'explication :


    3. j'aurai bien aimé utiliser le score de fulltext :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ${"selects".$sel} = "SELECT ".$etoile." , MATCH (".$etoile.") AGAINST ('+".$cherch."' IN BOOLEAN MODE) AS score FROM ".$table." WHERE MATCH (".$etoile.") AGAINST ('+".$cherch."' IN BOOLEAN MODE)";
    mais je ne vois pas comment introduire la notion de AND ou de OR avec union dans ce type de requete :


    4. ma notation et ma méthode sont-elles bonnes ? je ne trouve pas d'exemple ou de tutorial sur une recherche équivalente et je m'aperçoi que beaucoup de moteur de recherche ne tiennent pas compte de tout ça?

    Merci encore pour ces réponses , j'ai bien avancé et j'espère que ces résultats seront utiles à d'autres.

    hubidev

  6. #6
    Rédacteur

    Avatar de Yogui
    Homme Profil pro
    Directeur technique
    Inscrit en
    Février 2004
    Messages
    13 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Février 2004
    Messages : 13 721
    Points : 29 985
    Points
    29 985
    Par défaut
    Salut

    Désolé, ton sujet s'était perdu dans la masse :/


    1. Citation Envoyé par hubidev
      j'aurai préféré utiliser un tableau selects[] comme tu m'avais indiqué et faire $sql = implode(' UNION ', $selects); mais je ne sais pas comment ajouter des éléments: select[].="blabla"; ne marche pas, ça me génère un nouvelle entrée au tableau selects[]
      Non, ce n'est pas la bonne méthode.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      $array[] .= 'bouh';  // ceci est incorrect
       
      $array[] = $element; // ok
      $string .= 'bouh';   // ok
      L'idée des crochets [] est d'ajouter un élément à la fin d'un tableau. C'est un peu le .= des chaînes de caractères...
      Au départ, tu utilisais la concaténation (le point) pour compléter ta requète. Ma solution te permet de gérer séparément les éléments de ta requête (les SELECTs).
      Je te proposais d'ajouter toutes les requêtes indépendantes dans un tableau, puis d'utiliser implode() pour construire la requète finale avec le mot clef UNION. L'un des avantages était de te montrer que tes requêtes SELECT sont des requêtes à part entière et qu'UNION permet uniquement de rassembler les résultats de plusieurs requêtes SELECT dans un même groupement de résultats.


    2. Citation Envoyé par MySQL
      #1191 - Impossible de trouver un index FULLTEXT correspondant à cette liste de colonnes
      Aucune idée, il faudrait demander dans le forum MySQL pour avoir cette réponse. C'est une question purement MySQL, une fois que la requête est envoyée au SGBD. Rien à voir avec PHP, je suis bien incapable de te répondre.


    3. Citation Envoyé par hubidev
      je ne vois pas comment introduire la notion de AND ou de OR avec union dans ce type de requete
      cf. le point numéro 1 : utilise ma boucle pour générer des requêtes que tu peux tester indépendamment les unes des autres, puis utilise implode() pour grouper les résultats de toutes ces requètes à l'aide d'UNION.

Discussions similaires

  1. sql recherche sur plusieurs table / commande IN
    Par Tonio13006 dans le forum Langage SQL
    Réponses: 4
    Dernier message: 22/05/2008, 15h29
  2. Forger une requete de recherche sur plusieurs tables.
    Par robocop333 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 30/04/2008, 15h44
  3. Recherche sur plusieurs tables en même temps
    Par Zouzou1er dans le forum VBA Access
    Réponses: 5
    Dernier message: 09/10/2007, 10h40
  4. Recherche sur plusieurs tables
    Par micatmidog dans le forum Langage SQL
    Réponses: 2
    Dernier message: 09/06/2007, 17h28
  5. [MySQL] moteur de recherche sur plusieurs tables
    Par harlock59 dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 10/04/2007, 16h23

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