Gestion de périodes dans une table

Fermé
Sandra - Modifié le 4 juin 2020 à 16:21
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 - 5 juin 2020 à 15:49
Bonjour,

Je suis grande débutante en SQL et je n'arrive pas à coder la chose suivante.

J'ai une table avec les données suivantes (exemple simplifié) :

ma_table_initiale
Date                 Ville               Prenom    Valeur
31/03/18        Paris              Marie           1
30/06/18        Paris              Marie           1
30/09/18        Paris              Marie           0
31/12/18        Paris              Marie           0
30/06/19        Paris              Marie           1
31/03/19        Toulouse           Marie           1
30/09/19        Toulouse           Marie           0
31/12/19        Toulouse           Marie           1
31/03/30        Toulouse           Marie           1
31/03/18        Paris              Paul            1
30/09/19        Paris              Paul            1
31/12/19        Paris              Paul            0

etc...

Je cherche à obtenir la table suivante (c'est-à-dire en groupant les lignes par période sans que ces périodes ne se chevauchent) :
DateDébut          DateFin              Ville                Prenom               Valeur
31/03/18            30/06/18           Paris              Marie                    1
30/09/18            31/12/18           Paris              Marie                    0
30/06/19            30/06/19           Paris              Marie                    1
31/03/19            31/03/19           Toulouse           Marie                    1
30/09/19            30/09/19           Toulouse           Marie                    0
31/12/19            31/03/30           Toulouse           Marie                    1
31/03/18            30/09/19           Paris              Paul                     1
31/12/19            31/12/19           Paris              Paul                     0


En codant ceci :
insert into ma_table_finale            
 select min(f.Date), max(f.Date), f.Ville, f.Prenom, f.Valeur
        from ma_table_initiale f
 group by f.Ville, f.Prenom, f.Valeur;


J'obtiens évidemment une table dans laquelle les périodes se chevauchent :
DateDébut          DateFin              Ville             Prenom               Valeur
31/03/18            30/06/19           Paris           Marie                   1
30/09/18            31/12/18           Paris           Marie                   0
31/03/19            31/03/30           Toulouse        Marie                   1
30/09/19            30/09/19           Toulouse        Marie                   0
31/03/18            30/09/19           Paris           Paul                    1
31/12/19            31/12/19           Paris           Paul                    0


Auriez-vous une idée de comment coder cela?
Merci beaucoup à ceux qui me répondront,
Sandra
A voir également:

5 réponses

yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 Ambassadeur 1 550
4 juin 2020 à 19:35
bonjour,
je ne comprends pas ce que tu veux précisément obtenir.
peux-tu peut-être proposer un exemple plus simple, avec moins de colonnes?
0
Compliqué d'enlever des colonnes, il me semble qu'elles servent toutes pour montrer qu'il faut garder le détail.
J'explique avec des mots :
Dans la table de départ, j'ai une situation détaillée par date. Exemple avec (Paris, Marie):
ca vaut 1 sur 31/03/18,
1 sur 30/06/18
0 sur 30/09/18
0 sur 31/12/18
1 sur 30/06/19
Chaque ligne de la table porte sur 1 et une seule date.
Je veux exprimer les mêmes infos mais par période au lieu de par date.
Dans la table d'arrivée il y aurait donc, à la place de la colonne "Date", deux colonnes "Date début de période" et "Date fin de période".
Et ainsi les données sur (Paris, Marie) seraient représentées ainsi :
31/03/18            30/06/18           Paris              Marie                    1
30/09/18            31/12/18           Paris              Marie                    0
30/06/19            30/06/19           Paris              Marie                    1

=> La première ligne montre que ca vaut 1 sur la période 31/03/18 à 30/06/18
puis 0 sur la période 30/09/18 à 31/12/18
puis 1 sur la période 30/06/19 à 30/06/19

Avec le code que j'ai indiqué, ce n'arrive pas à cela mais à ceci :
31/03/18            30/06/19           Paris           Marie                   1
30/09/18            31/12/18           Paris           Marie                   0

Là la période de la 2ème ligne est contenue dans la période de la première ligne, cela ne me va pas.
Est-ce que c'est plus clair comme ca?
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 1 550
Modifié le 5 juin 2020 à 12:03
c'est plus clair, en effet. ville et prenom vont ensemble, tu aurais pu faire un exemple plus simple à comprendre avec une table à trois colonnes.
je ne sais pas si on va y arriver en SQL, je me demande si tu es vraiment obligée de le faire en SQL.
si je voulais essayer en SQL, je commencerais par faire ceci:
requete1:
select (f1.Date) as datedebut, min(f2.Date) as datefin, f1.Ville, f1.Prenom, 
               f1.Valeur as valeurdebut
        from ma_table_initiale f1, ma_table_initiale f2
        where f1.Ville = f2.Ville and f1.Prenom=f2.Prenom and f2.Date > f1.Date
        group by f.Date, f1.Ville, f1.Prenom,  f1.Valeur;

ensuite:
select r.*, f.valeur as valeurfin
from requete1 r, ma_table_initiale f
where r.Ville = f.Ville and f.Prenom=r.Prenom and r.datefin = f.Date
order by Ville, Prenom, datedebut

je ne suis pas convaincu que cela va nous permettre d'aboutir, et je pense que cela va dans la bonne direction.

EDIT: je pense qu'il va falloir adapter requete1 pour inclure les dernière périodes.
peut-être:
requete1:
select (f1.Date) as datedebut, min(f2.Date) as datefin, f1.Ville, f1.Prenom, 
               f1.Valeur as valeurdebut
        from ma_table_initiale f1 left join ma_table_initiale f2
        on f1.Ville = f2.Ville and f1.Prenom=f2.Prenom and f2.Date > f1.Date
        group by f.Date, f1.Ville, f1.Prenom,  f1.Valeur;
0
jee pee Messages postés 40470 Date d'inscription mercredi 2 mai 2007 Statut Modérateur Dernière intervention 23 novembre 2024 9 427
Modifié le 4 juin 2020 à 21:34
Bonjour,

A tester :
SELECT f.Date, NVL((SELECT g.Date FROM ma_table_initiale g 
                    WHERE f.Ville=g.ville AND f.Prenom=g.Prenom AND f.Valeur=g.Valeur
                       AND g.date > f.date
                    ORDER BY g.date
                    LIMIT 1),f.date), 
f.Ville, f.Prenom, f.Valeur
FROM ma_table_initiale f


0
Merci beaucoup pour votre réponse!
Il me semble que cela ne peut pas être la solution car le premier élément dans votre SELECT, c'est f.Date, donc j'aurai à l'arrivée autant de lignes qu'au départ alors que je devrais en avoir moins. Le premier élément devrait être le min d'un ensemble de dates il me semble.
0
jee pee Messages postés 40470 Date d'inscription mercredi 2 mai 2007 Statut Modérateur Dernière intervention 23 novembre 2024 9 427
4 juin 2020 à 22:20
Exact ! il ne faudrait pas ecrire de sql quand on n'a ni base, ni données pour tester ;-)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 Ambassadeur 1 550
Modifié le 5 juin 2020 à 16:20
voilà, j'ai fait ainsi, en utilisant une table simplifiée, tb (dt, cle, val), et en travaillant dans Access (tu devras sans doute remplacer iif par if).
une requête tbreqy1:
SELECT f1.cle, f1.dt, f1.val, min(iif(f2.dt is null,dateserial(2100,1,1),f2.dt)) AS datenext,
max(iif(f3.dt is null,dateserial(1900,1,1),f3.dt)) AS dateprev
FROM (tb AS f1 
LEFT JOIN tb AS f2 ON ((f1.val <>f2.val) AND (f1.dt<f2.dt) AND (f1.cle=f2.cle)))
LEFT JOIN tb AS f3 ON ((f1.val <>f3.val) AND (f1.dt>f3.dt) AND (f1.cle=f3.cle))
GROUP BY f1.cle, f1.dt, f1.val
ORDER BY f1.cle, f1.dt;

une requête tbreqy2:
SELECT r1.dt, r1.cle,r1.val,max(f1.dt) as datefin,min(f2.dt) as datedeb
from tbreqy1 r1, tb f1, tb f2
where r1.cle=f1.cle and f1.dt < r1.datenext
and r1.cle=f2.cle and f2.dt > r1.dateprev
group by r1.dt, r1.cle,r1.val
order by r1.cle,r1.dt
;

et ceci, qui donne le résultat:
SELECT distinct tbreqy2.cle, tbreqy2.val, tbreqy2.datedeb, tbreqy2.datefin
FROM tbreqy2
order by cle,datedeb;
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 1 550
Modifié le 5 juin 2020 à 16:18
le principe est assez simple:
- pour commencer, pour chaque enregistrement, on détermine les deux dates les plus proches, dans le passé et dans le futur, pour lesquelles la valeur est différente pour la combinaison (ville, prénom)
- ensuite, pour chaque enregistrement, on détermine les deux dates les plus éloignées, strictement situées dans la période déterminée à la première étape, pour la combinaison (ville,prénom)
- il suffit ensuite d'éliminer les doublons, et on obtient le résultat demandé
0