Requetes complexe

Eléphant du PHP | 80 Messages

03 janv. 2007, 11:57

Bonjour,

J'aimerais récupérer la liste des liens qui correspondent à tag1 ET tag3, c'est à dire, le lien1 ET le lien3. Je n'arrive pas à obtenir ce résultats en une seule requête.

Voici la table "links" :

Code : Tout sélectionner

+----+-------+---------------+ | id | title | url | +----+-------+---------------+ | 1 | lien1 | www.lien1.com | | 2 | lien2 | www.lien2.com | | 3 | lien3 | www.lien3.com | +----+-------+---------------+
La table "tags" :

Code : Tout sélectionner

+------+------+ | link | tag | +------+------+ | 1 | tag1 | | 1 | tag2 | | 1 | tag3 | | 2 | tag2 | | 2 | tag3 | | 3 | tag1 | | 3 | tag3 | +------+------+
Et le résultat espéré :

Code : Tout sélectionner

+----+-------+---------------+ | id | title | url | +----+-------+---------------+ | 1 | lien1 | www.lien1.com | | 3 | lien3 | www.lien3.com | +----+-------+---------------+
L'idéal serait de pouvoir trouver l'intersection de plusieurs requêtes de ce type:

Code : Tout sélectionner

SELECT links.id, links.title, links.url FROM tags, links WHERE tags.tag = 'tag1' AND tags.link = links.id
Mais je n'ai pas réussi à le faire...

Auriez-vous une solution?

Merci beaucoup,

PS : L'idéal serait que ce soit compatible avec MySQL 4.0.25.
Merci à tous!

Mammouth du PHP | 19672 Messages

03 janv. 2007, 12:15

Je ne saisis pas : quel résultat obtiens-tu au juste ? En reprenant exactement ta structure, j'obtiens bien le résultat attendu :-k

Voilà exactement ce que j'ai fait :

Code : Tout sélectionner

DROP TABLE IF EXISTS `links`; CREATE TABLE `links`( `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `title` VARCHAR(32) NOT NULL, `url` VARCHAR(128) NOT NULL )ENGINE = MyISAM; DROP TABLE IF EXISTS `tags`; CREATE TABLE `tags`( `link` INT(11) NOT NULL, `tag` VARCHAR(32) )ENGINE = MyISAM; INSERT INTO `links` VALUES (1, 'lien1', 'www.lien1.com'), (2, 'lien2', 'www.lien2.com'), (3, 'lien3', 'www.lien3.com'); INSERT INTO `tags` VALUES (1, 'tag1'), (1, 'tag2'), (1, 'tag3'), (2, 'tag2'), (2, 'tag3'), (3, 'tag1'), (3, 'tag3');
J'ai donc les tables :

Code : Tout sélectionner

mysql> SELECT * FROM `links`; +----+-------+---------------+ | id | title | url | +----+-------+---------------+ | 1 | lien1 | www.lien1.com | | 2 | lien2 | www.lien2.com | | 3 | lien3 | www.lien3.com | +----+-------+---------------+ 3 rows in set (0.00 sec) mysql> SELECT * FROM `tags`; +------+------+ | link | tag | +------+------+ | 1 | tag1 | | 1 | tag2 | | 1 | tag3 | | 2 | tag2 | | 2 | tag3 | | 3 | tag1 | | 3 | tag3 | +------+------+ 7 rows in set (0.00 sec)
Et j'obtiens :

Code : Tout sélectionner

mysql> SELECT links.id, links.title, links.url -> FROM tags, links -> WHERE tags.tag = 'tag1' -> AND tags.link = links.id; +----+-------+---------------+ | id | title | url | +----+-------+---------------+ | 1 | lien1 | www.lien1.com | | 3 | lien3 | www.lien3.com | +----+-------+---------------+ 2 rows in set (0.00 sec)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 80 Messages

03 janv. 2007, 12:20

Merci beaucoup pour ta réponse.

En fait, j'aimerais récupérer tout les liens qui ont le tag1 ET le tag3 (par exemple).

Dans l'exemple ici, il faudrait faire l'intersection de des deux requetes :

Code : Tout sélectionner

SELECT links.id, links.title, links.url FROM tags, links WHERE tags.tag = 'tag1' AND tags.link = links.id SELECT links.id, links.title, links.url FROM tags, links WHERE tags.tag = 'tag3' AND tags.link = links.id
Si tu effectue seulement la deuxième, tu obtiendra les trois lien alors que le lien2 n'a pas le tag1.

J'espère que je me suis fait comprendre.
Merci à tous!

Mammouth du PHP | 19672 Messages

03 janv. 2007, 13:39

J'espère que je me suis fait comprendre.
Un détail doit m'échapper, parce que... ben non, je comprends pas :-k

Le problème de toutes façons reste au niveau de ta version de MySQL : les sous-requêtes ne seront pas supportées par la 4.0 et ne le sont qu'à partir de la 4.1.

Donc il te reste la possibilité de traiter les résultats par programmation en stockant les retours des deux requêtes dans des tableaux indexés et en utilisant ensuite les fonctions de tableaux comme par exemple array_intersect()
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 80 Messages

03 janv. 2007, 14:22

Je pense que je vais utiliser array_intersect() pour ce cas-ci alors, merci.

Par contre, la requete que je cherche m'intéresse quand même (sous MySQL 5 alors).

Voilà quelques exemples de ce que j'aimerais que la requête fasse :
- Si je fais une recherche sur tag1 ET tag2, ma requête ne doit retourner QUE le lien1 étant donné que c'est le seul qui a ces DEUX tags.
- Si je fais une recherche sur tag1 ET tag2 ET tag3, ma requête ne doit retourner QUE le lien1 étant donné que c'est le seul qui a ces TROIS tags.
- Si je fais une recherche sur tag2 ET tag3, ma requête ne doit retourner QUE le lien1 et le lien2 étant donné que c'est les seul qui ont ces DEUX tags.
- Si je fais une recherche sur tag1 ET tag3, ma requête ne doit retourner QUE le lien1 et le lien3 étant donné que c'est les seul qui ont ces DEUX tags.


La requête que tu as essayée dans ton premier post ne cherche que sur un tag. J'aimerais pouvoir rechercher sur plusieurs tags, pour trouver des liens qui ont plusieurs tags en même temps.
Merci à tous!

Mammouth du PHP | 19672 Messages

03 janv. 2007, 14:40

Alors tu devrais explorer "IN" et la fonction SQL COUNT() qui pourrait permettre de créer une requête appropriée :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 80 Messages

03 janv. 2007, 16:01

Merci beaucoup, c'est exactement ce que je cherchais à faire!

Voilà ma requête finale pour ceux que ça intéresse :

Code : Tout sélectionner

SELECT id, title, url FROM links WHERE `id` IN(SELECT link FROM tags WHERE `tag` = 'tag1') AND `id` IN(SELECT link FROM tags WHERE `tag` = 'tag3');
Dommage que ce ne soit pas compatible avec MySQL 4.0 ...

Sujet résolu, merci beaucoup ;-)
Merci à tous!

Eléphant du PHP | 396 Messages

03 janv. 2007, 21:05

Si tu veux garder le IN avec MYSQL 4, tu peux faire 2 requêtes.

La 1ère qui te récupère les id que tu veux inclure dans le IN. Tu te debrouilles pour en faire une chaîne :
$les_in = '1,3,4';
La 2ème avec :
mysql_query=("SELECT id, title, url FROM links WHERE `id` IN(".$les_in.");

Eléphant du PHP | 80 Messages

03 janv. 2007, 23:42

Si tu veux garder le IN avec MYSQL 4, tu peux faire 2 requêtes.

La 1ère qui te récupère les id que tu veux inclure dans le IN. Tu te debrouilles pour en faire une chaîne :
$les_in = '1,3,4';
La 2ème avec :
mysql_query=("SELECT id, title, url FROM links WHERE `id` IN(".$les_in.");
J'était parti dans une solution avec array_intersect, mais celle que tu proposes est moins gourmande à mon avis.

Merci beaucoup!
Merci à tous!