IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

Requêtes sur plusieurs tables


Sujet :

Langage SQL

  1. #1
    Membre régulier Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Points : 118
    Points
    118
    Par défaut Requêtes sur plusieurs tables
    Bonjour,

    Je travail sur un script php de gestion de membres qui tourne autour d'un forum phpbb3 pour le compte d'une association.

    J'ai déjà programmer une gestion des comptes, je m'attaque maintenant à la gestion des cotisations à jour ou non.

    Le but : automatiser la suppression des membres des groupes 'associations' (group_id = 7, group_id = 11) les membres actifs 2009 qui n'ont pas payés la cotisation 2010

    Voici en gros l'algorithme des requêtes que je vais devoir effectuer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    //Req 1 : Qui a bien payé sa cotisation ?
    SELECT user_id
    FROM assoc_cotisations 
    WHERE cotisation_annee = 2010
    //' . date('Y', time() )
     
    //Req 2 : Quels sont les groupes qui ne payent pas la cotisation ?
    SELECT assoc_cotisations_types.cotisation_type_id 
    FROM assoc_cotisations_types 
    WHERE assoc_cotisations_types.cotisation_type_montant = 0 AND assoc_cotisations_types.cotisation_type_is_enable = 1
     
    //Req 3 : Quels sont les user_id qui ne payent pas la cotisation ?
    SELECT assoc_membres.user_id 
    FROM assoc_membres 
    WHERE assoc_membres.cotisation_type_id = {liste résultante de la requête 2}
     
    //Qui est dans les groupes 'associations' et doit payer une cotisation ?
    SELECT phpbb_user_group.user_id, phpbb_user_group.group_id
    FROM phpbb_user_group 
    WHERE ( phpbb_user_group.group_id = 7 OR phpbb_user_group.group_id = 11 ) AND phpbb_user_group.user_id != {liste résultante des requêtes 1 et 3}
     
    //On parcours les resultats et on supprime les utilisateurs des groupes
    while( $row = $db->sql_fetchrow($req) )
    {
    	group_user_del( $row['group_id'], $row['user_id'] );
    }

    Je me demandais s'il était possible de groupe ces requêtes en 1 seule et d'un point de vue 'performance' si c'était intéressant.

    (Même si c'est pas intéressant, j'aimerais savoir si c'est possible de faire ça et comment.)

    J'ai regarder du coté des jointures, mais je n'arrive pas à faire de jointure 'négative'

    Par exemple cette requête :
    Je voudrais qu'elle me retourne les user_id de ceux qui ont pour group_id 7 et qui ne sont pas dans la table cotisations

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT DISTINCT(phpbb_user_group.user_id, phpbb_user_group.group_id)
    FROM phpbb_user_group
    LEFT JOIN assoc_cotisations ON assoc_cotisations.user_id != phpbb_user_group.user_id
    WHERE phpbb_user_group.group_id = 7
    ORDER BY phpbb_user_group.user_id ASC
    Mais ça ne fonctionne pas

    Je me voit donc mal faire une requête qui exploite le résultat d'une autre

    Voici la structure simplifiée des tables :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    --
    -- Structure de la table `assoc_cotisations`
    --
     
    CREATE TABLE IF NOT EXISTS `assoc_cotisations` (
      `cotisation_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
      `user_id` mediumint(8) unsigned NOT NULL,
      `cotisation_annee` varchar(4) COLLATE utf8_bin NOT NULL,
      PRIMARY KEY (`cotisation_id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
     
    --
    -- Structure de la table `assoc_cotisations_types`
    --
     
    CREATE TABLE IF NOT EXISTS `assoc_cotisations_types` (
      `cotisation_type_id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
      `cotisation_type_montant` float unsigned NOT NULL,
      `cotisation_type_is_enable` tinyint(1) unsigned NOT NULL,
      PRIMARY KEY (`cotisation_type_id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
     
    --
    -- Structure de la table `assoc_membres`
    --
     
    CREATE TABLE IF NOT EXISTS `assoc_membres` (
      `user_id` mediumint(8) unsigned NOT NULL,
      `cotisation_type_id` tinyint(1) NOT NULL,
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
     
    --
    -- Structure de la table `phpbb_user_group`
    --
     
    CREATE TABLE IF NOT EXISTS `phpbb_user_group` (
      `group_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
      `user_id` mediumint(8) unsigned NOT NULL DEFAULT '0'
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    Merci par avance pour votre aide.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Bonjour,

    Vous pouvez essayer cette requête, avec des NOT EXISTS, qui correspondrait à ce que vous appelez 'jointure négative' :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    SELECT ug.user_id, ug.group_id
    FROM phpbb_user_group ug
    WHERE NOT EXISTS
    (
     SELECT * 
     FROM assoc_cotisations ac
     WHERE ac.user_id = ug.user_id
     AND ac.cotisation_annee = 2010
    )
    AND NOT EXISTS
    (
     SELECT *
     FROM assoc_membres am
     JOIN assoc_cotisations_types act ON am.cotisation_type_id = act.cotisation_type_id
     WHERE act.cotisation_type_montant = 0 AND act.cotisation_type_is_enable = 1
     AND ug.user_id = am.user_id
    )
    Au passage pour éviter le 2010 en codé en dur, vous pouvez récupérer l'année en cours en utilisant à la place EXTRACT(YEAR FROM current_date).

  3. #3
    Membre régulier Avatar de dark_vidor
    Homme Profil pro
    Élève
    Inscrit en
    Janvier 2005
    Messages
    321
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Élève

    Informations forums :
    Inscription : Janvier 2005
    Messages : 321
    Points : 118
    Points
    118
    Par défaut
    En rajoutant à la fin AND (ug.group_id = 7 OR ug.group_id = 11) ça à l'air de fonctionner

    J'suis pas sur d'avoir tout compris par contre faut que je regarde ça à tête reposé et que je pousse les tests un peu plus loin ...

    bien sur 2010, et les group_id font partis de variables donc dynamique en php

    merci pour votre aide et votre rapidité

    En terme de performance qu'es ce qui est le mieux ? faire plein de requêtes à la suite en 'traitant' en php les conditions ou le tout imbriqués comme proposé ici ?

    autant dire que la pour une requête qui sera exécutée 1 seule fois par ans, y'a aucun intérêt ... mais si jamais ça devait concerner une requête qui pourrait être effectuée plusieurs fois par minute ?

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    861
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 861
    Points : 965
    Points
    965
    Par défaut
    Ca dépend de beaucoup de choses (notamment de la modélisation et indexation de la BDD), mais la plupart du temps il est préférable de faire en SQL ce que vous pouvez faire en SQL (je parle de la récupération des données, pas de cosmétique pour l'affichage).
    Dans votre exemple, le faire en une seule requête sera à la fois plus simple et plus performant je pense.

Discussions similaires

  1. suite au problème de requête sur plusieur table
    Par michelGProuq dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 07/07/2006, 17h19
  2. [VB6] RecordSet, Oracle, requête sur plusieurs Tables
    Par pier* dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 13/04/2006, 11h19
  3. Requête sur plusieurs tables
    Par sta_schmitt dans le forum Requêtes
    Réponses: 2
    Dernier message: 28/03/2006, 14h54
  4. Requéte sur plusieurs tables
    Par polux23 dans le forum Requêtes
    Réponses: 11
    Dernier message: 24/02/2006, 00h00
  5. Requête sur plusieurs tables
    Par drinkmilk dans le forum Langage SQL
    Réponses: 8
    Dernier message: 11/07/2005, 13h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo