Page 1 sur 1
Requetes complexe
Posté : 03 janv. 2007, 11:57
par agilis
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.idMais 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.
Posté : 03 janv. 2007, 12:15
par Cyrano
Je ne saisis pas : quel résultat obtiens-tu au juste ? En reprenant exactement ta structure, j'obtiens bien le résultat attendu
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)
Posté : 03 janv. 2007, 12:20
par agilis
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.
Posté : 03 janv. 2007, 13:39
par Cyrano
J'espère que je me suis fait comprendre.
Un détail doit m'échapper, parce que... ben non, je comprends pas
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()
Posté : 03 janv. 2007, 14:22
par agilis
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.
Posté : 03 janv. 2007, 14:40
par Cyrano
Alors tu devrais explorer "
IN" et la fonction SQL
COUNT() qui pourrait permettre de créer une requête appropriée

Posté : 03 janv. 2007, 16:01
par agilis
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

Posté : 03 janv. 2007, 21:05
par Rei Itchido
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.");
Posté : 03 janv. 2007, 23:42
par agilis
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!