Précédent   Forum des professionnels en informatique > Bases de données > MySQL > Requêtes
Requêtes Forum d'entraide sur les requêtes MySQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 24/12/2010, 12h18   #1
Invité de passage
 
Inscription : décembre 2010
Messages : 24
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 24
Points : 1
Points : 1
Par défaut Demande aide sur requêtes SQL imbriquées

Bonjour,

Je souhaiterais obtenir de l’aide pour la construction d’un requête SQL – version MySQL: 4.0.21.

J’ai un formulaire qui permet de rechercher des membres (selon leur entreprise, leur nom, leur domaine…). Jusque-là tout roule.

Voici la requête d’affichage de mes membres actifs :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SELECT *
FROM Membre AS t1
LEFT JOIN Siret AS t2 ON (t2.SiretId = t1.SiretId)
LEFT JOIN Entreprise AS t3 ON (t3.SiretId=t1.SiretId)
WHERE t1.MembActif='1'
    AND 
    (
        (
            t1.MembConseiller='1' 
            AND 
            (
                t1.ProfilId ='2' 
                OR t1.ProfilId ='3'
            )
        ) 
        OR 
        (
            t1.MembConseiller='0' 
            AND t1.MembContact='1' 
            AND 
            (
                t1.ProfilId ='2' 
                OR t1.ProfilId ='3'
            )
        )
    )
ORDER BY t1.MembNom ASC 
LIMIT 0,20
Je dois également ajouter une recherche sur des actions des membres, sur le nombre de visites médicales et contre-visites qu’ils ont réalisés et entre une première date et une deuxième date.

Exemple texte : Visite réalisée entre le 01/09/2010 et le 24/12/2010.
La recherche sur les dates ne me pose pas de problème puisque la colonne existe dans la base.

Exemple texte : Visite entre 2 et 8
Par contre, pour la recherche sur la quantité de visites réalisée par membre, ce n’est pas en base de données

J’ai dans l’idée de faire une requête imbriquée:
Code :
1
2
3
SELECT COUNT(*) AS Nbvisites 
FROM Visite 
WHERE MembreId='".$data_rech[MembreId]."'

1 – Je dois faire une requête pour connaitre le nombre de visite de chaque membre
2 – Je dois vérifier si ce nombre se situe dans la tranche transmise par la recherche
3 – Je dois intégrer cette requête dans ma requête principale de recherche

Dois-je utiliser COUNT ou HAVING ou les deux ?

Avez-vous une idée et un exemple de la manière de construire la requête, merci d’avance.
pixworld2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/12/2010, 14h05   #2
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 980
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur d'études en informatique
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 10 980
Points : 18 224
Points : 18 224
Envoyer un message via MSN à CinePhil
D'abord, quelques remarques sur ta requête...

1) Évite la guerre des étoiles !

2) Inutile d'ajouter des parenthèses quand elles ne sont pas nécessaires.
Par exemple autour de tes conditions de jointure

3) Tes conditions de jointure sont faites sur le numéro de Siret qui est une mauvaise clé car non entière et susceptible de changer.

4) Inutile de mettre les valeurs des colonnes de type entier entre apostrophes.
Je suppose que ProfilId est de type entier auto-incrémenté non ?
Idem pour MembActif, MembConseiller et MembContact non ?

5) Plutôt que de faire A = x OR A = y, utilises IN
Code :
1
2
3
4
5
6
t1.ProfilId ='2'
OR t1.ProfilId ='3'
 
-- devient :
 
t1.ProfilId IN (2, 3)
En plus dans le cas présent ça t'économisera des parenthèses et ta requête sera plus facile à lire.

Voici ta requête récrite et simplifiée. Si je ne me suis pas trompé, elle devrait donner le même résultat.
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT les_colonnes_necessaires_et_pas_etoile
FROM Membre AS t1
LEFT JOIN Siret AS t2 ON t2.SiretId = t1.SiretId
LEFT JOIN Entreprise AS t3 ON t3.SiretId = t1.SiretId
WHERE t1.MembActif = 1
    AND t1.ProfilId IN (2, 3)
    AND
    (
        t1.MembConseiller = 1
        OR
        (
            t1.MembConseiller = 0 
            AND t1.MembContact = 1
        )
    )
ORDER BY t1.MembNom ASC 
LIMIT 0,20
Concernant maintenant ta demande...
Citation:
Je dois également ajouter une recherche sur des actions des membres, sur le nombre de visites médicales et contre-visites qu’ils ont réalisés et entre une première date et une deuxième date.

Exemple texte : Visite réalisée entre le 01/09/2010 et le 24/12/2010.
La recherche sur les dates ne me pose pas de problème puisque la colonne existe dans la base.

Exemple texte : Visite entre 2 et 8
Par contre, pour la recherche sur la quantité de visites réalisée par membre, ce n’est pas en base de données
Quel est le nombre de visites réalisées par les membres ?
Code :
1
2
3
SELECT MembreId, COUNT(*) AS nb_visites
FROM Visite
GROUP BY MembreId
Quel est le nombre de visites réalisées par les membres entre le 01/09/2010 et le 24/12/2010 ?
Code :
1
2
3
4
SELECT MembreId, COUNT(*) AS nb_visites
FROM Visite
WHERE VisiteDate BETWEEN '2010-09-01' AND '2010-12-24'
GROUP BY MembreId
Si tu ne veux garder que ceux qui ont réalisé entre 2 et 8 visites :
Code :
1
2
3
4
5
SELECT MembreId, COUNT(*) AS nb_visites
FROM Visite
WHERE VisiteDate BETWEEN '2010-09-01' AND '2010-12-24'
GROUP BY MembreId
HAVING COUNT(*) BETWEEN 2 AND 8
Intégration dans la requête principale :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SELECT les_colonnes_necessaires_et_pas_etoile
FROM Membre AS t1
INNER JOIN 
(
    SELECT MembreId, COUNT(*) AS nb_visites
    FROM Visite
    WHERE VisiteDate BETWEEN '2010-09-01' AND '2010-12-24'
    GROUP BY MembreId
    HAVING COUNT(*) BETWEEN 2 AND 8    
) AS tmp ON tmp.MembreId = t1.MembreId
LEFT JOIN Siret AS t2 ON t2.SiretId = t1.SiretId
LEFT JOIN Entreprise AS t3 ON t3.SiretId = t1.SiretId
WHERE t1.MembActif = 1
    AND t1.ProfilId IN (2, 3)
    AND
    (
        t1.MembConseiller = 1
        OR
        (
            t1.MembConseiller = 0 
            AND t1.MembContact = 1
        )
    )
ORDER BY t1.MembNom ASC 
LIMIT 0,20
Par contre, ceci pourrait poser problème :
Citation:
version MySQL: 4.0.21.
Je crois avoir vu quelque part que les sous-requêtes ne sont pas possibles en version 4 mais n'ayant jamais été confronté à cette version, je n'en suis pas sûr.
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/12/2010, 14h13   #3
Invité de passage
 
Inscription : décembre 2010
Messages : 24
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 24
Points : 1
Points : 1
Merci pour tes commentaires sur la requête existante, ça fait progresser et je teste immédiatement ta proposition de requête.

Merci beaucoup.
pixworld2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/12/2010, 15h08   #4
Invité de passage
 
Inscription : décembre 2010
Messages : 24
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 24
Points : 1
Points : 1
La requête est fonctionnelle sur notre serveur de test en MySQL: 5.0.44 mais pas sur le serveur du client en MySQL: 4.0.21.

je vais tenter de trouver une autre solution, certains évoquent la création d'une table temporaire, cela me semble trop contraignant.

Merci encore pour votre aide très appréciée.
Bonnes fêtes.
pixworld2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/12/2010, 15h19   #5
Modérateur
 
Avatar de CinePhil
 
Homme Philippe Leménager
Ingénieur d'études en informatique
Inscription : août 2006
Messages : 10 980
Détails du profil
Informations personnelles :
Nom : Homme Philippe Leménager
Âge : 48
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Ingénieur d'études en informatique
Secteur : Enseignement

Informations forums :
Inscription : août 2006
Messages : 10 980
Points : 18 224
Points : 18 224
Envoyer un message via MSN à CinePhil
Citation:
Envoyé par pixworld2 Voir le message
La requête est fonctionnelle sur notre serveur de test en MySQL: 5.0.44 mais pas sur le serveur du client en MySQL: 4.0.21.
C'est bien ce que je craignais !

Citation:
je vais tenter de trouver une autre solution, certains évoquent la création d'une table temporaire, cela me semble trop contraignant.
Pas tant que ça :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CREATE TEMPORARY TABLE tmp
SELECT MembreId, COUNT(*) AS nb_visites
FROM Visite
WHERE VisiteDate BETWEEN '2010-09-01' AND '2010-12-24'
GROUP BY MembreId
HAVING COUNT(*) BETWEEN 2 AND 8;
 
SELECT les_colonnes_necessaires_et_pas_etoile
FROM Membre AS t1
INNER JOIN tmp ON tmp.MembreId = t1.MembreId
LEFT JOIN Siret AS t2 ON t2.SiretId = t1.SiretId
LEFT JOIN Entreprise AS t3 ON t3.SiretId = t1.SiretId
WHERE t1.MembActif = 1
    AND t1.ProfilId IN (2, 3)
    AND
    (
        t1.MembConseiller = 1
        OR
        (
            t1.MembConseiller = 0 
            AND t1.MembContact = 1
        )
    )
ORDER BY t1.MembNom ASC 
LIMIT 0,20
__________________
Philippe Leménager. Ingénieur d'étude à l'École Nationale de Formation Agronomique.
Mon blog sur la conception des BDD, le langage SQL, le PHP avec Zend Framework...
« Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
À la maison comme au bureau, j'utilise Mandriva Linux ou Mageïa ! Soutenons l'industrie logicielle française !
Linuxiens, comptez-vous !
CinePhil est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 24/12/2010, 16h23   #6
Invité de passage
 
Inscription : décembre 2010
Messages : 24
Détails du profil
Informations forums :
Inscription : décembre 2010
Messages : 24
Points : 1
Points : 1
merci,
je vais mettre en place votre solution.
pixworld2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 11h11.


 
 
 
 
Partenaires

Hébergement Web