Vue d'ensemble
L'essentiel de la solution est une approche en 2 étapes. D'abord, considérons les enregistrements d'origine classés selon Date
et les enregistrements consécutifs avec la même valeur Field
étant groupés, en notant les dates maximale et minimale de chacun desdits groupes. Les enregistrements de l'ensemble de résultats généré décrivent les intervalles de date maximaux dans lesquels la valeur du champ ne change pas (cette sélection est encapsulée dans la vue vtest_lag
dans l'exemple sql ci-dessous)
Ensuite, rejoignez ce nouveau résultat avec un décalage de 1 sur l'une de sa colonne date. de cette façon, les intervalles adjacents sont jumelés dans le resultset finale, ce qui permet de mettre à jour Field
valeurs comme vous le souhaitez.
Avertissements
- la solution suppose aucune date double dans les données d'origine
- La solution ne porte pas sur l'efficacité
solution SQL
Cet exemple autonome est agnostique aux dialectes sql en dehors de rownum
pseudo-colonne Oracle fournissant le nombre ordinal d'un enregistrement dans un jeu de résultats. Il existe des fonctionnalités équivalentes dans d'autres arômes sql.
Partie 1/2: Configuration
create table test_lag (
t_date date
, field varchar2(10)
, desirednew varchar2(10)
, computednew varchar2(10)
);
insert into test_lag values (to_date ('01/09/1994', 'DD/MM/YYYY'), 'D', 'C' , null);
insert into test_lag values (to_date ('01/08/1994', 'DD/MM/YYYY'), 'D', 'C' , null);
insert into test_lag values (to_date ('01/07/1994', 'DD/MM/YYYY'), 'D', 'C' , null);
insert into test_lag values (to_date ('01/06/1994', 'DD/MM/YYYY'), 'C', 'B' , null);
insert into test_lag values (to_date ('01/05/1994', 'DD/MM/YYYY'), 'B', 'A' , null);
insert into test_lag values (to_date ('01/04/1994', 'DD/MM/YYYY'), 'B', 'A' , null);
insert into test_lag values (to_date ('01/03/1994', 'DD/MM/YYYY'), 'B', 'A' , null);
insert into test_lag values (to_date ('01/02/1994', 'DD/MM/YYYY'), 'A', null , null);
insert into test_lag values (to_date ('01/01/1994', 'DD/MM/YYYY'), 'A', null , null);
Partie 2/2: Mise à jour
Voir vtest_lag
encapsule la requête pour fournir les données de la déclaration de mise à jour.
create or replace view vtest_lag as
select emb.*
, rownum seq
from (
select *
from (
select sysdate t_date1
, null field1
, t_date t_date2
, field field2
from test_lag
where t_date = (select max(t_date) from test_lag)
union all
select t_date t_date1
, field field1
, to_date('01/01/1900', 'DD/MM/YYYY')
t_date2
, null field2
from test_lag
where t_date = (select min(t_date) from test_lag)
union all
select po1.t_date t_date1
, po1.field field1
, po2.t_date t_date2
, po2.field field2
from (
select po1_base.*
, rownum seq
from (
select *
from test_lag
order by t_date desc
) po1_base
) po1
join (
select po2_base.*
, rownum seq
from (
select *
from test_lag
order by t_date desc
) po2_base
) po2
on po2.seq = po1.seq + 1
where po1.field <> po2.field
)
order by t_date1 desc
) emb
;
update test_lag trg
set trg.computednew = (select v2.field2 from vtest_lag v1 join vtest_lag v2 on v2.seq = v1.seq+1 where trg.t_date <= v1.t_date2 and trg.t_date >= v2.t_date1)
;
Merci. Mes données sont plus compliquées et incluent des dates répétées, avec un autre champ de séquence. Je vais examiner votre réponse et l'apprécier grandement. Comme il ne voit pas comme une solution compacte existe, je peux importer les données à R où je peux faire la manipulation facilement en utilisant: – Patrick
out.i <- list ("vector") pour (i dans 1: nrow (dat)) { pour (j dans 1: nrow (dat)) { if ((dat [i, 2] == dat [ max (i, j), 2]) == FAUX) { out.i [[i]] <- data.frame (date [i,], dat [max (i, j), 2]) pause } else { out.I [[i]] <- data.frame (dat [i,], dat [max (i, j), 2])} }} outi <- do .call (rbind, out.i) colnames (outi) [3] <- "FieldNew" outi [3] <- ifelse (outi [, 2] == outi [, 3], "", as.character (outi [, 3])) – Patrick