Problème sur réquête avec jointure et recherche (LIKE)

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Problème sur réquête avec jointure et recherche (LIKE)

par supercanard » 26 mars 2008, 14:29

Merci pour toutes ses solutions :D
J'opte pour faire un tableau clean et nettoyé avant la requête.
$mots = strtolower( $_POST['recherche'] ); //Minuscule
	$tab_mots = explode( ' ', $mots ); // création tableau de mots-clé
	foreach ( $tab_mots AS $valeur )
	{
		if ( strlen( $valeur ) < 3 ) // On va supprimer les châine de moins de 3 caractères
		{
			unset( $tab_mots[array_search( $valeur, $tab_mots )] ); // Unset pour supprimer, array_search pour chercher la valeur à supprimer
		}
	}
Me reste plus qu'a trouvé une fonction magique pour remettre les clés d'applomb de 0 à x et pas avoir de trous entre sinon ça fait tout foirer la boucle de la requête ;)

par Ryle » 26 mars 2008, 12:26

Bah pour ça, ça dépend beaucoup du contexte et des choses que tu peux rechercher...

Personnellement, si je tape "boîte de chocolat", c'est plus la chaine entière que je m'attends à retrouver plutôt que l'un ou l'autre des mots... Donc on peut supposer que ton moteur de recherche propose ces différentes option : "n'importe quel mot" (pour lequel ton script fonctionne) ou "la chaine exacte" (auquel cas il suffit de remplacer ta boucle par une valeur unique, avec un simple test :)). Tu peux aussi pousser le vice à "tous les mots", même boucle mais avec des AND :)

Pour en revenir aux articles (pronoms, conjonction, etc.), puisque c'est de là que vient le problème, une solution peut être de faire un tableau contenant ces mots usuels ( array('le', 'la', 'les', 'de', 'du', ...)) et d'utiliser array_diff() pour les supprimer de ton tableau $tab_mots avant la boucle lorsque la recherche se fait sur n'importe lequel de ces mots.

Maintenant, tu peux aussi très bien utiliser la commande "continue" dans ta boucle si le mot fait moins de 3 caractères pour passer directement au suivant sans ajouter de condition dans la requête :) C'est beaucoup plus rapide à mettre en place, mais c'est aussi plus restrictif.. une fois encore, ça dépend du contexte et des termes utilisés sur ton site :)

par supercanard » 26 mars 2008, 12:14

Ah ça me parait beaucoup plus clair et je comprends donc tout vas bien.

Maintenant je vais essayer de pousser un peu plus loin car j'ai rencontré un problème embattant :

Si l'on lance une recherche de ce type : "armoire a cuillere"

Il y a problème. La recherche peut renvoyer un nombre incalculable de résultat puisque "a" se trouve forcément dans beaucoup de mots.

Je pensais à une piste : supprimer du tableau les chaine ne contenant qu'un seul caractère, puisqu'une recherche avec un seul caractère n'est pas vraiment une recherche...

Mais le problème se posera aussi avec deux caractères...
Exemple : "bôite de chocolat" : Va renvoyer les entrés contenant : "bôite de chocolat", mais aussi "bôite de raviolis" ( rien de grave) mais aussi "demarcher", ce qui n'a rien à voir, mais comme de est dans la chaine...

Solution : ne garder que les mots d'au moins 3 caractères dans ma variable de recherche ?

par Ryle » 26 mars 2008, 11:33

mais du coup je comprends pas ton exemple car tu fait allusion aux parantheses mais tu n'en n'utilise pas...
Ah... tiens... oui... c'est très juste... c'est ce que dans le jargon technique on qualifie communnément de... boulette ;)

En fait, comme pour le HTML, il faut partir du code SQL que tu veux obtenir. L'idée ici c'est d'avoir :

Code : Tout sélectionner

AND ( condition1 OR condition2 OR condition3 ... )
on a donc un "AND ()" et une boucle sur les conditions en intercallant un OR entre chaque. Mon code corrigé donnerait donc ceci :
$recherche = ' AND (';  
for ( $i = 0; $i < count($tab_mots); $i++ ) { // On boucle sur les mots et on les ajoute à la requête   
  if ($i > 0)  // on ne commence à ajouter les OR qu'après le premier élément
    $recherche.= ' OR '; 
  $recherche .= 'ipi3_notes_texte LIKE \'%'.$tab_mots[$i].'%\'';  
}
$recherche.= ')';

J'en profite pour commencer la boucle à $i=0 :)

par supercanard » 26 mars 2008, 00:07

J'y ai pensé aux parantheses, j'avais essayé ça au hasard :
$recherche =  '(AND ipi3_notes_texte LIKE \'%'.$tab_mots[0].'%\'';
	for ( $i = 1; $i < $nb_mots; $i++ ) // On boucles tous les mots et on les ajoutent à la requête
	{
  		$recherche .= 'OR ipi3_notes_texte LIKE \'%'.$tab_mots[$i].'%\'';
	}
	$recherche .= ')';
mais du coup je comprends pas ton exemple car tu fait allusion aux parantheses mais tu n'en n'utilise pas...
Je te fait confiance il est surement juste, mais comment faire "avec parantheses" ? Mon essai n'est pas juste sans trop de surprise il renvoi une erreur : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(AND ipi3_notes_texte LIKE '%a%'OR ipi3_notes_texte LIKE '%de%') AND ipi3_libel' at line 5

par Ryle » 25 mars 2008, 23:25

N'oublies pas que l'opérateur ET est prioritaire sur le OU comme la multiplication sur l'addition, si tu n'utilises pas de parenthèse. En gros : "a ET b OU c OU d" équivaut à "soit a et b", "soit c", "soit d"

Essayes comme ceci :
$recherche = ' AND '; 
for ( $i = 0; $i < count($tab_mots); $i++ ) { // On boucles tous les mots et on les ajoutent à la requête  
  if ($i > 0) 
    $recherche.= ' OR ';
  $recherche .= 'ipi3_notes_texte LIKE \'%'.$tab_mots[$i].'%\''; 
}

Problème sur réquête avec jointure et recherche (LIKE)

par supercanard » 25 mars 2008, 21:06

Bonjour,
Je me met doucement aux jointures SQL et là je rencontre une difficulté dansu n cas particulier sans doute du à une mauvaise compréhension...
Tout allé bien jusqu'à que je décide de faire un mini moteur de recherche à l'aide de LIKE et OR.

Je vais essayer d'expliquer ma requête ou plutôt le résultat recherché.
Je recherche les données d'une table appartenant l'utilisateur identifié ( {$_SESSION['utilisateur']} ).
Et j'ajoute une condition si la variable recherche est envoyé qui est de récupérer seulement les lignes ou le champ spécifié contient au moins un des mots clés du tableau.
Seulement j'ai été obligé de faire une boucle sur la partie recherche de la requête et d'utiliser OR.

Au final, je ne sais expliquer pourquoi car j'ai surement mal comprit quelque chose, mais j'obtiens des résultat dont l'id utilisateur ne correspond plus à l'utilisateur identifié mais à tout le monde.

Si quelqun pouvais me mettre sur une piste ça m'aiderait beaucoup... :wink:
if ( isset( $_POST['recherche'] ) ) // Recherche
{
	$mots = strtolower( $_POST['recherche'] ); //Minuscule
	$tab_mots = explode( ' ', $mots ); // création tableau de mots-clé
	$nb_mots = count( $tab_mots ); // On compte le nombre de mots dans le tableau
	$recherche =  'AND ipi3_notes_texte LIKE \'%'.$tab_mots[0].'%\'';
	for ( $i = 1; $i < $nb_mots; $i++ ) // On boucles tous les mots et on les ajoutent à la requête
	{
  		$recherche .= 'OR ipi3_notes_texte LIKE \'%'.$tab_mots[$i].'%\'';
	}
}
else
{
	$recherche = NULL;
}
$req_notes = "SELECT * 
FROM ipi3_notes, ipi3_libelles 
WHERE ipi3_notes_gens_id = {$_SESSION['utilisateur']} 
AND ipi3_notes_etat = 1 
$recherche 
AND ipi3_libelles_id = ipi3_notes_libelles_id 
{$_SESSION['pref_ordrenotes']}";
$result_notes = mysql_query( $req_notes ) or die( mysql_error() );
echo $req_notes;