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

SQL Firebird Discussion :

Pbm de requête : Utilisation d'une requête récursive ?


Sujet :

SQL Firebird

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Décembre 2004
    Messages
    390
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 390
    Par défaut Pbm de requête : Utilisation d'une requête récursive ?
    Bonjour,

    Voilà, j'ai une table COTIS avec comme champs : ID_EMP, MOIS_COTIS et MONTANT. Elle contient les cotisations mensuelles des employés.

    La requête que je n'arrive pas à mettre en oeuvre est la suivante :

    Savoir si un employé à cotisé pour les mois : JANVIER, FEVRIER, MARS ET AVRIL en ayant comme entrés l'Id de l'employé, le mois de débu (Janvier)) et le mois de la fin (Avril)

    Merci d'avance,

    W7, D7, FB2.5

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 664
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 664
    Billets dans le blog
    65
    Par défaut
    Bonjour,

    Cela aurait été sympa (et plus rapide) de nous fournir un script de création de tables et un jeu d'essai
    comme par exemple ceci (perfectible car pas d'index)
    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
     
    CREATE TABLE Employes
    ( ID_EMP INTEGER NOT NULL,
      NOM VARCHAR(20)
    );
    CREATE TABLE COTISATIONS
    (ID_EMP INTEGER NOT NULL,
     MOIS SMALLINT NOT NULL,
     MONTANT NUMERIC(15,2)
    );
     
    COMMIT;
    INSERT INTO EMPLOYES VALUES (1,'toto tout');
    INSERT INTO EMPLOYES VALUES (2,'tata partiel');
    INSERT INTO EMPLOYES VALUES (3,'titi rien');
     
    INSERT INTO COTISATIONS VALUES(1,1,10); -- paiement en 2 fois
    INSERT INTO COTISATIONS VALUES(1,1,10); -- 2° paiement
    INSERT INTO COTISATIONS VALUES(1,2,20);
    INSERT INTO COTISATIONS VALUES(1,3,20);
    INSERT INTO COTISATIONS VALUES(1,4,20);
    INSERT INTO COTISATIONS VALUES(2,1,20);
    -- pas de paiement de l'employé 2 mois 2      
    INSERT INTO COTISATIONS VALUES(2,3,10); -- paiement en 2 fois
    INSERT INTO COTISATIONS VALUES(2,3,10); -- 2° paiement
    INSERT INTO COTISATIONS VALUES(2,4,20);
    Comme j'aime bien scinder les problèmes voici ma solution, utilisant à la fois une requête récursive et une CTE
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    -- Liste des employes n'ayant pas payé de cotisation entre les mois 1 et 4 
    WITH 
       -- récupérer les mois voulus (il suffiras de remplacer par des paramètres)
       RECURSIVE MONTHS(M) AS (select 1 AS M from RDB$DATABASE   -- 1 à remplacer par paramètre mois de début
                                        union all 
                                        select m+1 from MONTHS 
                                        where m < 4                                      -- 4 à remplacer par paramètre mois de fin 
                                 ),
      -- récupérer les couples mois/employé (tous les employés pour tous les mois) 
        EMPMOIS AS (SELECT MONTHS.M,E.ID_EMP FROM MONTHS FULL JOIN EMPLOYES E ON 1=1)
    -- Obtenir les employés n'ayant rien versé      
    SELECT E.M,E.ID_EMP,C.MONTANT FROM EMPMOIS E LEFT JOIN COTISATIONS C ON E.ID_EMP=C.ID_EMP AND E.M=C.MOIS
    WHERE MONTANT IS NULL
    Cette requête est perfectible, je suis sûr que l'on peut faire plus "condensé", mais elle fonctionne

  3. #3
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 925
    Par défaut
    Salut à tous.

    Citation Envoyé par akli_agha
    Savoir si un employé à cotisé pour les mois : JANVIER, FEVRIER, MARS ET AVRIL en ayant comme entrés l'Id de l'employé, le mois de début (Janvier)) et le mois de fin (Avril).
    Ce que tu demandes est assez facile à faire.
    Si un employé donné a cotisé durant quatre mois, de janvier (1) à avril (4), normalement, le nombre de lignes dans la table sera de quatre.

    pour ce faire, j'ai fait une procédure stockée avec les paramètres suivants :
    --> identifiant de l'employé
    --> début du mois en nombre
    --> fin du mois en nombre

    J'ai mis aussi une contrainte, la clef primaire est constitué du couple (id_emp ; mois_cotis).

    L'employé '1' a cotisé durant 5 mois sans interruption.
    L'employé '2' a des trous durant la même période.

    S'il n'y a pas de trous, le résultat sera 'T' pour TRUE, c'est-à-dire VRAI.
    S'il y a des trous, le résultat sera 'F' pour FALSE, c'est-à-dire FAUX.

    Voici ce que cela donne :
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    CREATE DATABASE '..\Data\Base.fdb' page_size 4096 DEFAULT CHARACTER SET ISO8859_1;
     
    -- ============================
    -- Création de la table 'cotis'
    -- ============================
     
    CREATE TABLE cotis (
      ID_EMP      INTEGER       NOT NULL,
      MOIS_COTIS  SMALLINT      NOT NULL,
      MONTANT     DECIMAL(15,2) NOT NULL,
      PRIMARY KEY (ID_EMP,MOIS_COTIS)
    );
     
    -- ======================
    -- Insertion dans 'cotis'
    -- ======================
     
    insert into cotis (id_emp, mois_cotis, montant) values (1, 1, 100.00);
    insert into cotis (id_emp, mois_cotis, montant) values (1, 2, 100.00);
    insert into cotis (id_emp, mois_cotis, montant) values (1, 3, 100.00);
    insert into cotis (id_emp, mois_cotis, montant) values (1, 4, 100.00);
    insert into cotis (id_emp, mois_cotis, montant) values (1, 5, 100.00);
     
    insert into cotis (id_emp, mois_cotis, montant) values (2, 1, 150.00);
    insert into cotis (id_emp, mois_cotis, montant) values (2, 4, 150.00);
    insert into cotis (id_emp, mois_cotis, montant) values (2, 5, 150.00);
     
    -- =================
    -- Vidage de 'cotis'
    -- =================
     
    select * from cotis;
     
          ID_EMP MOIS_COTIS               MONTANT
    ============ ========== =====================
               1          1                100.00
               1          2                100.00
               1          3                100.00
               1          4                100.00
               1          5                100.00
               2          1                150.00
               2          4                150.00
               2          5                150.00
     
     
    -- ==================
    -- Creation Procédure
    -- ==================
     
    SET TERM $;
    create procedure test(emp integer,
                          deb smallint,
                          fin smallint)
    returns (result char(01))
    as
      declare diff smallint;
      declare calc smallint;
    begin
      diff = fin - deb + 1;
     
      select count(distinct mois_cotis)
      from   cotis
      where  id_emp = :emp
        and  mois_cotis between :deb and :fin
      group by id_emp
      into calc;
     
      if (diff = calc) then result = 'T'; else result = 'F';
      suspend;
    end$
    SET TERM ;$
     
    -- ===================
    -- Execution procédure
    -- ===================
     
    select * from test(1, 1, 4);
     
    RESULT
    ======
    T
     
    select * from test(2, 1, 4);
     
    RESULT
    ======
    F
     
     
    exit;
     
    Appuyez sur une touche pour continuer...
    Le résultat que nous proposons dépend essentiellement de tes explications.
    Une simplification de ton problème n'est pas la garantie d'avoir le résultat que tu recherches.

    @+

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 664
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 664
    Billets dans le blog
    65
    Par défaut
    Bonjour,

    en fait ce qui me chiffonne le plus dans cette table COTIS c'est l'indication d'un MOIS au lieu d'une date certainement beaucoup plus appropriée dés qu'il va s'agir d'une utilisation sur la durée.

  5. #5
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 925
    Par défaut
    Bonjour SergioMaster.

    Oui, en effet, tu as raison. Cette notion de mois est assez floue.
    Il faudrait que le mois soit composé de l'année + mois, par exemple "201605".

    @+

  6. #6
    Membre éclairé
    Inscrit en
    Décembre 2004
    Messages
    390
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 390
    Par défaut
    Excusez les amis, j'ai été cloué un bon bout de temps .


    Au fait, j'ai mis mois mais en réalité ce sont des cotisations par année !
    Je n'ai pas cru que vous alliez y prêter attention !

    Désolé !

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 664
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 664
    Billets dans le blog
    65
    Par défaut
    Bonjour,
    Citation Envoyé par akli_agha Voir le message
    Je n'ai pas cru que vous alliez y prêter attention !
    ne pas y prêter attention alors que c'était l'occasion de tester une requête récursive ? c'est mal me connaitre
    Citation Envoyé par akli_agha Voir le message
    Au fait, j'ai mis mois mais en réalité ce sont des cotisations par année !
    cela ne change pas grand chose, la seule chose qui à mon sens serait pertinente c'est d'indiquer si par employé il n'y a qu'une seule cotisation par critère (par an donc).

    l'hypothèse pour moi était 0,n cotisations par employé par mois (ou année) et je reste persuadé qu'une requête récursive plus compacte est possible, mais sans réponse à ma première proposition j'avais laissé tomber

  8. #8
    Membre éclairé
    Inscrit en
    Décembre 2004
    Messages
    390
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 390
    Par défaut
    Merci Sergio.

    Tant mieux pour votre ténacité !

    Pour les cotisations, c'est 0, 1 cotisation par année. Soit l'employé paie soit le contraire.

    Et merci pour tout.

  9. #9
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 925
    Par défaut
    Salut à tous.

    Citation Envoyé par SergioMaster"
    cela ne change pas grand chose, la seule chose qui à mon sens serait pertinente c'est d'indiquer si par employé il n'y a qu'une seule cotisation par critère (par an donc).
    En fait, la question est mal posée.
    Imaginons qu'une personne trouvant le montant de cette cotisation un peu trop élevé, paye en plusieurs fois.
    La question est de savoir, si à la date d'échéance d'une période, cette personne s'est acquittée de la totalité de sa cotisation.

    Ensuite, il faut vérifier si cette personne s'est acquittée de toutes ses cotisations et ce, sur plusieurs périodes.
    Ce que j'ai cherché à faire est de vérifier s'il y a, par exemple sur quatre périodes, bien quatre cotisations.
    Autrement dit, une cotisation par période, et s'il y a quatre période, il y a quatre cotisations.

    @ akli_agha : j'aimerai savoir si nos solutions sont satisfaisantes ou pas ?
    Et en quoi on peut l'améliorer pour répondre à votre attente.

    @+

  10. #10
    Membre éclairé
    Inscrit en
    Décembre 2004
    Messages
    390
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 390
    Par défaut
    Bien évidemment que les que les solutions proposées sont satisfaisantes et je vous en remercie !

    Pour revenir à notre soucis, l'employé paie en totalité sa cotisation. Il ne peut pas la payer en plusieurs tranches

    Encore une fois, meric.

Discussions similaires

  1. [MSSQL 2K5] PBM pour mixer deux requêtes en une seule
    Par fredfred dans le forum Langage SQL
    Réponses: 6
    Dernier message: 05/07/2010, 15h12
  2. Utilisation de MAX dans une requête SQL
    Par Evil onE dans le forum Langage SQL
    Réponses: 7
    Dernier message: 15/06/2004, 18h38
  3. Requete requête sous sybase
    Par eddie dans le forum Sybase
    Réponses: 3
    Dernier message: 02/04/2003, 14h51
  4. Requête imbriquée et indexes INTERBASE
    Par vadim dans le forum InterBase
    Réponses: 2
    Dernier message: 06/09/2002, 16h15
  5. [BDD] Enregistrer le résultat d'une requête
    Par Mowgly dans le forum C++Builder
    Réponses: 5
    Dernier message: 19/06/2002, 15h26

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