Requête un peu compliquée

VaN
Mammouth du PHP | 1107 Messages

12 févr. 2008, 16:41

Bonjour,

j'ai une table CONCOURS, une TABLES USERS, et une TABLE ASSOC, que voici :
CREATE TABLE `concours` (
`concours_id` int(11) NOT NULL auto_increment,
`concours_user_id` int(11) NOT NULL,
`concours_site_id` int(11) NOT NULL,
`concours_url` text NOT NULL,
`concours_reglement_url` text NOT NULL,
`concours_start_date` datetime NOT NULL,
`concours_end_date` datetime NOT NULL,
`concours_type` tinyint(4) NOT NULL,
`concours_participation` tinyint(11) NOT NULL,
`concours_qs` enum('Oui','Non') NOT NULL,
`concours_nb_reponses` tinyint(4) NOT NULL,
`concours_lots` text NOT NULL,
`concours_rating` tinyint(4) NOT NULL,
`concours_activated` tinyint(4) NOT NULL,
PRIMARY KEY (`concours_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

CREATE TABLE `users` (
`user_id` int(11) NOT NULL auto_increment,
`user_login` text character set latin1 collate latin1_general_cs NOT NULL,
`user_pass` text character set latin1 collate latin1_general_cs NOT NULL,
`user_mail` text NOT NULL,
`user_level` tinyint(4) NOT NULL,
`user_activated` tinyint(4) NOT NULL,
`user_activation_key` text character set latin1 collate latin1_general_cs NOT NULL,
`user_logged` tinyint(4) NOT NULL,
`user_last_session` datetime NOT NULL,
`user_last_ip` text NOT NULL,
`user_points` int(11) NOT NULL,
`user_parrain_id` int(11) NOT NULL,
`user_scoot_activated` tinyint(4) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=24 ;

CREATE TABLE `assoc` (
`assoc_user_id` int(11) NOT NULL,
`assoc_concours_id` int(11) NOT NULL,
`assoc_statut` enum('','done','ignored') NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
je souhaiterai afficher la liste des concours, pour un utilisateur donné (j'ai son $_SESSION['user_id']), qui n'ont pas de correspondance dans la table ASSOC. Cette table ASSOC sert à savoir si un utilisateur à fait/ignoré un concours. Lorsque l'utilisateur fait cette requete, cela ajoute une entrée dans la table, avec le concours_id, le user_id, et le statut ('done', 'ignored').

La, j'aimerai qu'une requete sortent tous les concours qui ne sont ni faits, ni ignorés, donc qui n'ont pas encore de correspondance dans la table ASSOC.

j'en suis pour le moment à la, mais je bloque sur la fin de la requete :
$sql = 	"SELECT concours_id, site_name, concours_end_date, concours_type_title, concours_rating
			FROM ".$prefixe."concours, ".$prefixe."concours_type, ".$prefixe."sites, ".$prefixe."assoc
			WHERE concours_type = concours_type_id
			AND concours_site_id = site_id
			AND concours_id = assoc_concours_id
			AND concours_activated = 1
			AND assoc_user_id = '".$_GET['user_id']."'";

d0m
Mammouth du PHP | 1141 Messages

12 févr. 2008, 16:50

Tu peux utiliser une sous requête :
Sélectionner les concours qui ne sont pas dans la table assoc :

Code : Tout sélectionner

SELECT concours_id,.... FROM concours WHERE concours_id NOT IN (SELECT DISTINCT concours_id FROM assoc)

VaN
Mammouth du PHP | 1107 Messages

12 févr. 2008, 17:19

mhh je ne connaissais ni NOT IN, ni l'imbrication de requête. merci, je vais aller voir de ce côté.

EDIT :

Alors, j'ai un peu modifié la requête. Elle me sort bien le concours (le seul) qui correspond aux critères que j'ai cité plus haut (ni fait, ni ignoré), mais elle me le sort en 2 exemplaires. Pourquoi donc ?
<?php
$sql = "SELECT concours_id, site_name, concours_end_date, concours_type_title, concours_rating 
FROM concours, concours_type, sites, assoc 
WHERE concours_type = concours_type_id 
AND concours_site_id = site_id 
AND concours_activated = 1 
AND concours_id NOT IN (SELECT DISTINCT assoc_concours_id FROM assoc WHERE assoc_user_id = '".$_GET['user_id']."')"; ?>

VaN
Mammouth du PHP | 1107 Messages

13 févr. 2008, 20:49

up du topic, pour mettre le flag 'new post' pour les connaisseurs SQL qui trainent sur ce forum, car j'ai édité mon message, depuis mon dernier post.

Soit dit en passant, le système anti-spam (pas pouvoir répondre si on est l'auteur du dernier post) est parfois très embêtant, car en éditant un message, on apporte parfois pleins d'infos supplémentaires, mais le msg ne passe pas en 'new post'.

[Note : ce message a été posté de manière anonyme avant d'être réattribué à son auteur]

Modérateur PHPfrance
Modérateur PHPfrance | 7636 Messages

13 févr. 2008, 23:10

Pourquoi y a-t-il un champ "concours_user_id" dans la table "concours" si la table assoc doit faire le lien entre "concours" et "user" :-k

Tu n'as pas de clé sur la table "assoc"... une clé double sur "assoc_user_id, assoc_concours_id" seraot pas mal.

Pour ton souci manquerait bien une jointure de table avec "assoc".

Essaie avec cette requête :

Code : Tout sélectionner

SELECT concours_id FROM concours LEFT JOIN assoc ON concours_id = assoc_concours_id JOIN concours_type ON concours_type = concours_type_id JOIN sites concours_site_id = site_id WHERE concours_activated = 1 AND concours_id NOT IN (SELECT DISTINCT assoc_concours_id FROM assoc WHERE assoc_user_id = 1 )

/!\ Avant de poster se documenter et rechercher.
Qui ne sait pas rendre un service n'a pas le droit d'en demander.
MaBrute

VaN
Mammouth du PHP | 1107 Messages

14 févr. 2008, 01:55

Pourquoi y a-t-il un champ "concours_user_id" dans la table "concours" si la table assoc doit faire le lien entre "concours" et "user" :-k
Parce que la table assoc stockent le lien entre un utilisateur et une réponse (elle stocke le fait que cet utilisateur a fait ou ignoré ce concours). Le concour_user_id lui permet de savoir quel utilisateur a enregistré ce concours dans la table CONCOURS. Ce sont donc 2 choses différentes.
Tu n'as pas de clé sur la table "assoc"... une clé double sur "assoc_user_id, assoc_concours_id" seraot pas mal.
Ok pour ça, je vais m'en occuper.
Pour ton souci manquerait bien une jointure de table avec "assoc".

Essaie avec cette requête :

Code : Tout sélectionner

SELECT concours_id FROM concours LEFT JOIN assoc ON concours_id = assoc_concours_id JOIN concours_type ON concours_type = concours_type_id JOIN sites concours_site_id = site_id WHERE concours_activated = 1 AND concours_id NOT IN (SELECT DISTINCT assoc_concours_id FROM assoc WHERE assoc_user_id = 1 )
merci pour la réponse, je test ça demain soir et te tiens au courant, la je vais me coucher.

VaN
Mammouth du PHP | 1107 Messages

14 févr. 2008, 23:16

Pourquoi y a-t-il un champ "concours_user_id" dans la table "concours" si la table assoc doit faire le lien entre "concours" et "user" :-k
Parce que la table assoc stockent le lien entre un utilisateur et une réponse (elle stocke le fait que cet utilisateur a fait ou ignoré ce concours). Le concour_user_id lui permet de savoir quel utilisateur a enregistré ce concours dans la table CONCOURS. Ce sont donc 2 choses différentes.
Je me suis emmêlé les pinceaux, la table ASSOC stocke le fait qu'un utilisateur a fait ou ignoré un concours. On m'a conseillé de créer cette table car avant, j'enregistrais les ID des concours faits et ignorés directement dans la table USERS, dans des champs prévus à cette effet (user_concours_done et user_concours ignored), où les ID des concours etaient séparées par des ";".
Tu n'as pas de clé sur la table "assoc"... une clé double sur "assoc_user_id, assoc_concours_id" seraot pas mal.
C'est bien des clé primaire qu'il faut mettre sur ces deux champs ?
Pour ton souci manquerait bien une jointure de table avec "assoc".

Essaie avec cette requête :

Code : Tout sélectionner

SELECT concours_id FROM concours LEFT JOIN assoc ON concours_id = assoc_concours_id JOIN concours_type ON concours_type = concours_type_id JOIN sites concours_site_id = site_id WHERE concours_activated = 1 AND concours_id NOT IN (SELECT DISTINCT assoc_concours_id FROM assoc WHERE assoc_user_id = 1 )
Et concernant cette requête, bin nickel, elle fonctionne parfaitement, manquait juste un ON sur le 3e JOIN. Après correction, elle me sort bien seulement les concours ni faits, ni ignorés.

Merci beaucoup : )

Modérateur PHPfrance
Modérateur PHPfrance | 7636 Messages

15 févr. 2008, 00:36

Tu n'as pas de clé sur la table "assoc"... une clé double sur "assoc_user_id, assoc_concours_id" seraot pas mal.
C'est bien des clé primaire qu'il faut mettre sur ces deux champs ?
Oui

/!\ Avant de poster se documenter et rechercher.
Qui ne sait pas rendre un service n'a pas le droit d'en demander.
MaBrute

VaN
Mammouth du PHP | 1107 Messages

15 févr. 2008, 19:51

Tu n'as pas de clé sur la table "assoc"... une clé double sur "assoc_user_id, assoc_concours_id" seraot pas mal.
C'est bien des clé primaire qu'il faut mettre sur ces deux champs ?
Oui
J'arrive bien à mettre une Primary Key sur concours_assoc_id, mais lorsque j'essaie de la mettre sur assoc_user_id, je reçois le message d'erreur suivant :
#1062 - Duplicata du champ '1' pour la clef 1
je ne le comprend pas bien.

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

15 févr. 2008, 19:58

Cela signifie que tu as, dans ta table, plusieurs enregistrements dont le champs assoc_user_id vaut 1.

Le truc que tu n'as pas compris, c'est qu'il ne faut pas une clé primaire sur assoc_concours_id, puis une autre sur assoc_user_id (soit dit en passant, avoir plusieurs clés primaires sur une table n'est pas possible, il faudrait que tu te renseignes sur ce qu'est réellement une clé primaire ;)) mais une seule clé primaire qui porte sur les 2 champs
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

VaN
Mammouth du PHP | 1107 Messages

15 févr. 2008, 20:22

Cela signifie que tu as, dans ta table, plusieurs enregistrements dont le champs assoc_user_id vaut 1.

Le truc que tu n'as pas compris, c'est qu'il ne faut pas une clé primaire sur assoc_concours_id, puis une autre sur assoc_user_id (soit dit en passant, avoir plusieurs clés primaires sur une table n'est pas possible, il faudrait que tu te renseignes sur ce qu'est réellement une clé primaire ;)) mais une seule clé primaire qui porte sur les 2 champs
Mhh, il me semblait bien aussi que avoir deux PK dans une table etait impossible. Si je comprend bien ce que tu dis, il faut en fait que je crée un champs assoc_id dans cette table, que je spécifie en tant que PK (et en auto increment) ?

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

15 févr. 2008, 20:44

non, non, du tout ;)

Il faut que tu crées une clé primaire sur les 2 champs en même temps.

Si tu crées tes tables avec PhpMyAdmin, faut que tu supprimes l'index qui s'appelle "PRIMARY" et que tu créé un nouvel index portant sur les 2 champs portant ce nom là.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

VaN
Mammouth du PHP | 1107 Messages

15 févr. 2008, 21:01

non, non, du tout ;)

Il faut que tu crées une clé primaire sur les 2 champs en même temps.

Si tu crées tes tables avec PhpMyAdmin, faut que tu supprimes l'index qui s'appelle "PRIMARY" et que tu créé un nouvel index portant sur les 2 champs portant ce nom là.
MMhh ok, je viens de le faire sous PHPmyAdmin, je me retrouve avec un tableau de ce genre, sous la structure de ma table, donc j'imagine que c'est bon :

Index
Nom de la clé | Type | Cardinalité | Champ
PRIMARY | PRIMARY | 2 | assoc_user_id, assoc_concours_id

je n'avais jamais fait ça avant. Quel est le but ?

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

15 févr. 2008, 21:11

le but d'une clé primaire est d'identifier de manière unique un enregistrement dans la table.
Cela signifie que si tu interroge ta table en mettant la clé primaire comme condition, tu auras un seul résultat.

Pour une table d'association, c'est à dire qui associe deux tables, comme dans ton cas, il ne doit y avoir qu'une seule association entre 2 enregistrements de tes différentes tables (cf. un joueur ne peut participer qu'une seule fois à chaque jeu concours).

Pour t'assurer de ça, il suffit de mettre en place une clé primaire entre l'id du concours et l'id du joueur.

Est-ce que c'est plus clair ?
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

VaN
Mammouth du PHP | 1107 Messages

15 févr. 2008, 21:21

Oui, je comprend mieux.