使用 SAS 或 SQL 查找一行中的第一个和最后一个非空值?
Using SAS or SQL find the first and last non-empty value within a row?
我的数据目前的格式是:
ID Fill1 Fill2 Fill3 Fill4 Fill5
1 01JAN2014 28JAN2014 26FEB2014 . .
2 . 05FEB2012 03MAR2012 02APR2012 01MAY2012
3 10MAR2015 08APR2015 07MAY2015 05JUN2015 03JUL2015
4 . . 20FEB2013 18MAR2013 .
我正在尝试为每个 ID 创建治疗 "episodes"。换句话说,对于每个 ID 我想找到第一个和最后一个非空 Fills,然后计算两个日期之间的差异。例如,对于 ID=1,我需要找出 01JAN2014 和 26FEB2014 之间的时差。也就是说,
填充 1 - 填充 3 = 剧集持续时间
但对于 ID=4,我需要找到
Fill3 - Fill4 = 剧集持续时间
其中 episodeduration 是创建的新变量。我有超过 30k 个具有不同 "first" 和 "last" 填充日期的唯一 ID。在此先感谢您的帮助。
data have;
input Id Fill1 date9. Fill2 date9. Fill3 date9. Fill4 date9. Fill5 date9.;
format Fill1 - Fill5 date9.;
cards;
1 01JAN201428JAN201426FEB2014
2 05FEB201203MAR201202APR201201MAY2012
3 10MAR201508APR201507MAY201505JUN201503JUL2015
4 20FEB201318MAR2013
;
run;
data want;
set have;
array fill {5};
format first last date9.;
do i = 1 to dim(fill);
first=coalesce(first, fill(i));
last=coalesce(fill(i), last);
end;
episodeduration = last - first;
drop i;
run;
使用 array
语句创建数组并循环变量和 coalesce()
函数查找 first/last 非缺失。
注释:此代码将通过从第一个变量到最后一个变量来查找 first/last。如果在日期方面需要 first/last,min 和 max 函数很好:min(of fill1 -- fill5);
- 无需循环。
vasja 的 SAS 版本看起来很不错,下面是如何在 SQL 方面完成(这几乎完全相同的过程)。
Select *,
DATEDIFF(day,
CONVERT(date,COALESCE(date1, date2, date3, date4, date5)),
CONVERT(date, COALESCE(date5,date4,date3,date2,date1))
)
from SomeTableNameAboutEpisodes;
基本上,您使用 coalesce 找到第一个非空值,然后将其转换为日期。然后您计算这两个日期之间的差值。但是,这仅在空单元格没有值(空)并且没有空行时才有效。 (不过你可以简单地放一个 ISNULL(DATEDIF(...), 0))。
您可以使用降序 "SAS Variable List" (FILL5-FILL1) 使这更容易一些。
data diff;
set have;
first = coalesce(of fill1-fill5);
i = whichn(first,of fill1-fill5);
last = coalesce(of fill5-fill1);
j = 6-whichn(last, of fill5-fill1);
format first last date9.;
run;
Obs Id Fill1 Fill2 Fill3 Fill4 Fill5 first i last j
1 1 01JAN2014 28JAN2014 26FEB2014 . . 01JAN2014 1 26FEB2014 3
2 2 . 05FEB2012 03MAR2012 02APR2012 01MAY2012 05FEB2012 2 01MAY2012 5
3 3 10MAR2015 08APR2015 07MAY2015 05JUN2015 03JUL2015 10MAR2015 1 03JUL2015 5
4 4 . . 20FEB2013 18MAR2013 . 20FEB2013 3 18MAR2013 4
我的数据目前的格式是:
ID Fill1 Fill2 Fill3 Fill4 Fill5
1 01JAN2014 28JAN2014 26FEB2014 . .
2 . 05FEB2012 03MAR2012 02APR2012 01MAY2012
3 10MAR2015 08APR2015 07MAY2015 05JUN2015 03JUL2015
4 . . 20FEB2013 18MAR2013 .
我正在尝试为每个 ID 创建治疗 "episodes"。换句话说,对于每个 ID 我想找到第一个和最后一个非空 Fills,然后计算两个日期之间的差异。例如,对于 ID=1,我需要找出 01JAN2014 和 26FEB2014 之间的时差。也就是说,
填充 1 - 填充 3 = 剧集持续时间
但对于 ID=4,我需要找到
Fill3 - Fill4 = 剧集持续时间
其中 episodeduration 是创建的新变量。我有超过 30k 个具有不同 "first" 和 "last" 填充日期的唯一 ID。在此先感谢您的帮助。
data have;
input Id Fill1 date9. Fill2 date9. Fill3 date9. Fill4 date9. Fill5 date9.;
format Fill1 - Fill5 date9.;
cards;
1 01JAN201428JAN201426FEB2014
2 05FEB201203MAR201202APR201201MAY2012
3 10MAR201508APR201507MAY201505JUN201503JUL2015
4 20FEB201318MAR2013
;
run;
data want;
set have;
array fill {5};
format first last date9.;
do i = 1 to dim(fill);
first=coalesce(first, fill(i));
last=coalesce(fill(i), last);
end;
episodeduration = last - first;
drop i;
run;
使用 array
语句创建数组并循环变量和 coalesce()
函数查找 first/last 非缺失。
注释:此代码将通过从第一个变量到最后一个变量来查找 first/last。如果在日期方面需要 first/last,min 和 max 函数很好:min(of fill1 -- fill5);
- 无需循环。
vasja 的 SAS 版本看起来很不错,下面是如何在 SQL 方面完成(这几乎完全相同的过程)。
Select *,
DATEDIFF(day,
CONVERT(date,COALESCE(date1, date2, date3, date4, date5)),
CONVERT(date, COALESCE(date5,date4,date3,date2,date1))
)
from SomeTableNameAboutEpisodes;
基本上,您使用 coalesce 找到第一个非空值,然后将其转换为日期。然后您计算这两个日期之间的差值。但是,这仅在空单元格没有值(空)并且没有空行时才有效。 (不过你可以简单地放一个 ISNULL(DATEDIF(...), 0))。
您可以使用降序 "SAS Variable List" (FILL5-FILL1) 使这更容易一些。
data diff;
set have;
first = coalesce(of fill1-fill5);
i = whichn(first,of fill1-fill5);
last = coalesce(of fill5-fill1);
j = 6-whichn(last, of fill5-fill1);
format first last date9.;
run;
Obs Id Fill1 Fill2 Fill3 Fill4 Fill5 first i last j
1 1 01JAN2014 28JAN2014 26FEB2014 . . 01JAN2014 1 26FEB2014 3
2 2 . 05FEB2012 03MAR2012 02APR2012 01MAY2012 05FEB2012 2 01MAY2012 5
3 3 10MAR2015 08APR2015 07MAY2015 05JUN2015 03JUL2015 10MAR2015 1 03JUL2015 5
4 4 . . 20FEB2013 18MAR2013 . 20FEB2013 3 18MAR2013 4