[SQL] Une requete bien compliquée

Une requete bien compliquée [SQL] - PHP - Programmation

Marsh Posté le 17-08-2010 à 00:02:40    

Bonsoir,
 
Je travaille en php avec mysql, et j'ai besoin de faire une requete que je n'arrive pas à formaliser algorithmiquement
 
J'explique mon problème.
Dans ma table j'ai notamment 5 colonnes, que l'on appellera C1, ... C5 (et qui sont telles que les pour une ligne donnée, la valeur dans la colonne 1 est inférieure ou égale à celle de la colonne 2, elle même inférieure ou égale à la valeur de la colonne 3 et ainsi de suite...) .
J'ai aussi une colonne id (les ids de chacun des enregistrements sont tous différents) (je ne sais pas si ca peut vous servir par la suite, mais je précise tout de meme que je dispose de cette colonne id)
 
J'ai un nombre de variables k compris entre 1 et 5 (on va dire qu'elles sont triées de manière croissante, si ca peut aider...)
 
Ce que je veux faire, c'est déterminer les lignes pour lesquelles on trouve les valeurs de toutes les variables dans les colonnes C1 à C5.
Mais attention, si deux de mes variables ont la même valeur, pour qu'une ligne soit sélectionnée, il faut que la valeur apparaisse deux fois.
 
 
Je ne sais pas si j'ai été très clair, je vais donc faire un petit exemple
 
 
Disons que j'ai k=3
$v1=1
$v2=3
$v3=4
 
C1 -- C2 -- C3 -- C4 -- C5
 0       1      3       4      5   -> OK
 0       2      3       4      5  -> Pas OK (le 1 n'est dans aucune des colonnes)
 
 
Maintenant si j'ai  
$v1=1
$v2=3
$v3=3
 
C1 -- C2 -- C3 -- C4 -- C5
 0       1      3       4      5   -> Pas ok, j'ai deux variables à 3, il faut donc au moins deux apparitions de "3" dans mes colonnes (et les autres variables doivent apparaitre également)
 0       1      2       3      3   -> OK
 0       1      3       3      3   -> OK
 
 
 
 
Dans un premier temps, je pensais faire quelque chose comme ca

Code :
  1. "... WHERE (C1=$v1 OR C2=$v1 OR C3=$v1 OR C4=$v1 OR C5=$v1) AND (C1=$v2 OR C2=$v2 OR C3=$v2 OR C4=$v2 OR C5=$v2) AND (C1=$v3 OR C2=$v3 OR C3=$v3 OR C4=$v3 OR C5=$v3)


 
Le problème, c'est que ca fait un gros paquet de conditions (et je sais pas trop si sql va apprécié); mais surtout que dans le cas ou deux variables sont égales, et bien la requête ne fonctionne pas correctement.
 
 
J'aurais donc besoin de votre aide, parce que ca fait un petit bout de temps que je suis là dessus, et à vrai dire, je sèche :(
 
Merci d'avance :)


Message édité par nisalon_caje le 17-08-2010 à 00:04:50
Reply

Marsh Posté le 17-08-2010 à 00:02:40   

Reply

Marsh Posté le 17-08-2010 à 01:39:12    

je pense que tu prends le problème à l'envers  
 
un truc comme ça ne marcherai t il pas ?  
 
WHERE $v1 IN (c1,c2,c3,c4,c5) AND $v2 IN (c1,c2,c3,c4,c5) AND $v3 IN (c1,c2,c3,c4,c5)
 
vu que c'est classé, tu peux optimiser un peu ( toujours pas bien sur, il est tard )
 
WHERE $v1 IN (c1,c2,c3) AND $v2 IN (c2,c3,c4) AND $v3 IN (c3,c4,c5)

Reply

Marsh Posté le 17-08-2010 à 01:46:50    

salut,
 
tu n'as pas précisé si tu voulais faire cela entièrement en sql ou bien via php
 
voilà un début de solution (un p'tit temps libre :) ):
 

Code :
  1. <?php
  2. //définition des valeur à trouver
  3. $variables = array(1,3,3);
  4. //récuperes ici tes champs C1 à C5 pour tel ID
  5. $bdd = array(3,1,5,2,3);
  6. //comptabilisation des valeurs par fréquence d'apparition
  7. $bddfield_by_values = array_count_values($bdd);
  8. //on ne récupère que la fréquence pour les valeurs que tu as spécifié dans $variables
  9. $only_variables = array_intersect_key($bddfield_by_values,array_flip($variables));
  10. var_dump($only_variables);
  11. ?>


il est désormais simple, pour chacune de tes valeurs, de savoir si le nombre d'apparitions est >= à ce que tu souhaites


Message édité par Profil supprimé le 17-08-2010 à 01:48:09
Reply

Marsh Posté le 17-08-2010 à 10:48:29    

@flo -> ton truc ne marchera pas, puisque si par exemple j'ai v1=2 v2=2 v3=2 et
 
c1=1 c2=2 c3=3 c4=4 c5=5, ta requete sortira cette ligne là alors que le 2 n'apparait qu'une seule fois
 
 
@spike, cela fonctionne :)
Le seul problème avec ta méthode, est le fait que si ma table fait 100 000 enregistrements, j'ai peur que ce soit un peu long en traitement :(
En fait je comptais le faire plutôt dans une requete sql pour pouvoir placer des index derrière pour essayer d'accélérer le tout ...
Mais bon ta solution marche très bien !


---------------
http://nisalon.labrute.com/
Reply

Marsh Posté le 17-08-2010 à 12:39:19    

J'ai trouvé une solution qui fonctionne, mais qui n'est pas très jolie, en repartant du IN de flo850 :

 
Code :
  1. $k=count($variables);
  2. switch($k){
  3. case 0:
  4. $conditions="";
  5. break;
  6. case 1:
  7. $conditions="$variables[0] IN (C1,C2,C3,C4,C5)"
  8. break;
  9. case 2:
  10. $conditions="($variables[0],$variables[1]) IN ((C1,C2),(C1,C3),(C1,C4),(C1,C5),(C2,C3),(C2,C4),(C2,C5),(C3,C4),(C3,C5),(C4,C5))";
  11. break;
  12. case 3:
  13. $conditions="($variables[0],$variables[1],$variables[2]) IN ((C1,C2,C3),(C1,C2,C4),(C1,C2,C5),(C1,C3,C4),(C1,C3,C5),(C1,C4,C5),(C2,C3,C4),(C2,C3,C5),(C2,C4,C5),(C3,C4,C5))";
  14. break;
  15. case 4:
  16. $conditions="($variables[0],$variables[1],$variables[2],$variables[3]) IN ((C1,C2,C3,C4),(C1,C2,C3,C5),(C1,C2,C4,C5),(C1,C3,C4,C5),(C2,C3,C4,C5))";
  17. break;
  18. case 5:
  19. $conditions="$variables[0]=C1 AND $variables[1]=C2 AND $variables[2]=C3 AND $variables[3]=C4 AND $variables[4]=C5";
  20. break;
  21. }
  22. $sql="SELECT ... WHERE $conditions";
 

C'est pas super joli, mais j'ai l'avantage que je peux facilement utiliser d'autres instructions telles limit, group by etc etc

 


Si quelqu'un sait comment optimiser ça, je suis preneur :) (d'autant plus qu'un explain indique la non prise en compte des index, meme si l'on crée un index sur chaque colonne, sur chaque couple de colonne, sur chaque triplet de colonnes ...)


Message édité par nisalon_caje le 17-08-2010 à 12:48:22

---------------
http://nisalon.labrute.com/
Reply

Marsh Posté le 17-08-2010 à 22:56:35    

oh my god!  Vu l'heure ou j'avais rédigé mon idée, j'ai pas percuté que t'avais un ordre croissant dans tes colonnes C1->C5
 
en fait tu peux le faire avec une simple requete sql :
 
soit tes chiffres 1 3 3 :  
 
cela te renvoi les lignes contenant forcément 1 3 3, meme si un "2" se loge entre, et basta :
 

Code :
  1. SELECT id, concat( C1,  '-', C2,  '-', C3,  '-', C4,  '-', C5 )  AS myconcat
  2. FROM  `test`
  3. GROUP  BY id
  4. HAVING myconcat LIKE  '%1%3%3%'


si par contre, les valeurs recherchés doivent apparaitre forcément à la suite, tu peux remplacer par cela, peut etre moins lourd :

Code :
  1. SELECT ...
  2. HAVING myconcat LIKE '%1-3-3%'


what else?
et on se fiche du nombre de variables à checker, t'as juste ta chaine à construire


Message édité par Profil supprimé le 17-08-2010 à 22:57:58
Reply

Marsh Posté le 17-08-2010 à 23:11:28    

merci spike :)


Message édité par nisalon_caje le 17-08-2010 à 23:55:40

---------------
http://nisalon.labrute.com/
Reply

Marsh Posté le 17-08-2010 à 23:57:36    

Oula ca me semblait bon, mais en fait nan :(

 

C1 C2  C3  C4  C5
 1  31  32  45  66

 

La requête remonte la ligne alors qu'elle n'est pas correcte.
je regarde si rajouter des tirets avant les % ne pourrait pas nous aider

 

Edit : si on faisait par exemple ...

Code :
  1. SELECT ...
  2. HAVING myconcat LIKE  '%1-%3-%3-%'

, avoir
C1 C2  C3  C4  C5
 1  13  23 45  66

 

serait correct, alors que ca ne l'est pas

 

et si on mets un tiret avant, un tiret apres,

Code :
  1. SELECT ...
  2. HAVING myconcat LIKE  '%-1-%-3-%-3-%'

, et ben ca marche pas non plus, puisqu'on se retrouve potentiellement avec 1--3 (alors qu'on ne met jamais de -- dans notre concat) et au début c'est galère

 

Apparemment, il faut faire un

Code :
  1. concat( '-',C1,  '--', C2,  '--', C3,  '--', C4,  '--', C5 ,'-')
 

et pour générer la chaine à rechercher :

Code :
  1. %-$variables[0]-%-$variables[1]-%-$variables[2]-%-...-%-$variables[k]-%


Message édité par nisalon_caje le 18-08-2010 à 00:08:15

---------------
http://nisalon.labrute.com/
Reply

Marsh Posté le 18-08-2010 à 01:13:22    

normal, t'avais pas précisé que les valeurs pouvaient être des nombres sur deux chiffres, alternative bien trouvée

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed