如何获取sas中日期列的第二个最大和第三个最大记录

How to get the second max and third max records of date column in sas

我想获取下面的最大值、第二最大值和第三最大值日期table

proc SQL;

create table Kri_obs_l(
  Kri_rk int,
  value_dt datetime,
  score int
);

insert into Kri_obs_l
values (10000, "2Jan2018"d, 12)
values (10001, "2Jan2018"d, 2)
values (10001, "29Jan2019"d, 18)
values (10002, "2Jan2018"d, 5)
values (10002, "26Jan2019"d, 18)
values (10002, "27Jan2019"d, 18)
values (10003, "2Jan2018"d, 18)
values (10003, "26Jan2019"d, 18)
values (10003, "27Jan2019"d, 18)
values (10004, "2Jan2018"d, 25)
values (10005, "2Jan2018"d, 32)
values (10005, "26Jan2019"d, 18)
values (10005, "27Jan2019"d, 18)
values (10006, "2Jan2018"d, 5)
values (10007, "2Jan2018"d, 2)
values (10008, "2Jan2018"d, 12)
values (10009, "2Jan2018"d, 18)
values (10009, "26Jan2019"d, 18)
values (10009, "27Jan2019"d, 18)
;
quit;

我获取最大值、第二个最大值和第三个最大值的代码

proc sql;
create table KRI_score_max as
select Kri_rk, MAX(value_dt) as reported_dt format=date9.
from KRI_OBS_l
group by Kri_rk;

create table KRI_score_second_max as
select Kri_rk, MAX(value_dt) as reported_dt format=date9.
from KRI_OBS_l a
where value_dt = (select MAX(value_dt) from KRI_OBS_l b where value_dt< (select MAX(value_dt) from KRI_OBS_l))
group by Kri_rk;

create table KRI_score_third_max as
select Kri_rk, MAX(value_dt) as reported_dt format=date9.
from KRI_OBS_l
where value_dt < (select MAX(value_dt) from KRI_OBS_l where value_dt< (select MAX(value_dt) from KRI_OBS_l))
group by Kri_rk;

create table KRI_score_third_max as
select * 
from KRI_score_third_max
where KRI_rk in (select Kri_rk from KRI_score_second_max);

quit;

获取最大记录工作正常,我在获取第二个最大记录和第三个最大记录时遇到问题 如果我从 table 中删除 29Jan2019 记录,它工作正常,但添加该记录会使 27Jan2019 成为第二个最大记录,因此查询将此记录作为第二个最大记录。 我想通过 Kri_rk.

获得每个记录组的第二个最大和第三个最大记录

由于proc中没有任何limit函数SQL,我不能使用order by desc和limit组合。

如果你想要第一到第三个最大日期,你可以使用 row_number() window 函数

select * from 
(
select * ,row_number() over(partition by Kri_rk order by value_dt desc) rn
from table_name
) t where t.rn<=3

您将在第二个语句中排除第一个创建的结果 table,然后从第三个查询中排除前两个 table。

proc sql;
create table KRI_score_max as
select Kri_rk, MAX(value_dt)  first_max as reported_dt format=date9.
from KRI_OBS_l
group by Kri_rk;

create table KRI_score_second_max as
select Kri_rk, MAX(value_dt) second_max as reported_dt  format=date9.
from KRI_OBS_l a
where (kri_rk, value_dt) not in (select kri_rk, first_max from KRI_score_max)
group by Kri_rk
UNION ALL 
select Kri_rk, MAX(value_dt) second_max as reported_dt format=date9. from KRI_OBS_l a group by Kri_rk having count(1)<2;

create table KRI_score_third_max as
select Kri_rk, MAX(value_dt) third_max as reported_dt format=date9.
from KRI_OBS_l
where (kri_rk, value_dt) not in (select kri_rk, first_max from KRI_score_maxl UNION ALL select kri_rk, second_max from KRI_score_second_max)
UNION ALL  
(select Kri_rk, MAX(value_dt) third_max as reported_dt format=date9. from KRI_OBS_l a group by Kri_rk having count(1)<3
MINUS
select Kri_rk,second_max from KRI_score_max); 

quit;

由于您正在使用 SAS,因此请使用 proc summary 中的 idgroup 功能。以下代码将每组的前 3 个日期存储在单独的列中(尽管您没有明确说明您希望如何存储数据)。

proc summary data=Kri_obs_l nway;
class kri_rk;
output out=want (drop=_:)
    idgroup(max(value_dt) out[3] (value_dt) = reported_dt);
run;

简单的触发等级应该有效

proc rank data=Kri_obs_l out=inter descending ties=dense;
   by  Kri_rk;
  var value_dt ;
  ranks value_dt_1; 
 run; 

data final(drop=value_dt_1);
  set inter;
 if value_dt_1 le 3;
 run;

假设如果每个 id 的日期没有重复项,那么下面的查询也应该有效

  proc sort data =Kri_obs_l out =Kri_obs_l_1;
     by  Kri_rk descending value_dt;
   run;

  data want;
    set Kri_obs_l_1;
  by  Kri_rk descending value_dt;
 if first.Kri_rk then m=1;
 else m+1;
   if m le 3;
 drop m;
   run;


   proc sql;
  create table want(drop=cnt) as 
     select Kri_rk, value_dt, score,
       (select count(value_dt) from Kri_obs_l a
    where a.Kri_rk = b.Kri_rk
   and a.value_dt ge b.value_dt
   group by Kri_rk) as cnt
   from Kri_obs_l b 
   where calculated cnt le 3
   ;

有很多选项可以解决这个问题。我更喜欢重用您的代码并在您的过程中进行调整 sql。我 运行 下面的代码成功了。

proc sql;
create table KRI_score_max as
select Kri_rk, MAX(value_dt) as reported_dt format=date9.
from KRI_OBS_l
group by Kri_rk;
quit;

proc sql;
create table KRI_score_second_max as
select a.Kri_rk, MAX(a.value_dt) as reported_dt format=date9.
from KRI_OBS_l a
where a.value_dt not in (Select reported_dt from Kri_score_max b where 
a.kri_rk=b.kri_rk)
group by a.Kri_rk;

quit;

proc sql;
create table KRI_score_third_max as
select a.Kri_rk, MAX(a.value_dt) as reported_dt format=date9.
from KRI_OBS_l a
where a.value_dt not in (Select reported_dt from Kri_score_max b where 
a.kri_rk=b.kri_rk) and 
a.value_dt not in (Select reported_dt from KRI_score_second_max b where 
a.kri_rk=b.kri_rk) 
group by a.Kri_rk;
quit;