Gestion de périodes dans une table
Sandra
-
yg_be Messages postés 23541 Date d'inscription Statut Contributeur Dernière intervention -
yg_be Messages postés 23541 Date d'inscription Statut Contributeur Dernière intervention -
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
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) :
En codant ceci :
J'obtiens évidemment une table dans laquelle les périodes se chevauchent :
Auriez-vous une idée de comment coder cela?
Merci beaucoup à ceux qui me répondront,
Sandra
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:
- Gestion de périodes dans une table
- Table ascii - Guide
- Table des matières word - Guide
- Logiciel gestion locative gratuit excel - Télécharger - Comptabilité & Facturation
- Gestion de fichiers - Télécharger - Gestion de fichiers
- Logiciel gestion photo gratuit - Guide
5 réponses
yg_be
Messages postés
23541
Date d'inscription
Statut
Contributeur
Dernière intervention
Ambassadeur
1 584
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?
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?
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 :
=> 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 :
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?
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?
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:
ensuite:
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:
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;
Bonjour,
A tester :
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
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.
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.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
yg_be
Messages postés
23541
Date d'inscription
Statut
Contributeur
Dernière intervention
Ambassadeur
1 584
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:
une requête tbreqy2:
et ceci, qui donne le résultat:
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;
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é
- 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é