Самое общее решение будет включать полное внешнее объединение в каждой группе.
SQL может выполнять объединение и вычислять месяцы отдельно для случая месяца с N по умолчанию до следующего самого раннего месяца с D по умолчанию. Табуляция может представлять сетку отсчетов.
Данные
Строки месяца преобразуются в значения даты SAS 1-го числа месяца, отформатированные yymon
для целей отображения.
data have;
input Date $ Acc $ Default $;
month = input ('01-'||date, date9.);
format month yymon.;
datalines;
jan-10 A N
feb-10 A D
mar-10 A D
apr-10 A D
may-10 A D
jan-10 B N
feb-10 B N
mar-10 B D
apr-10 B D
may-10 B D
jan-10 C N
feb-10 C N
mar-10 C N
apr-10 C D
may-10 C D
jan-10 D N
feb-10 D D
mar-10 D N
apr-10 D D
may-10 D D
jan-10 E D
feb-10 E D
mar-10 E D
apr-10 E N
may-10 E D
run;
Пример SQL
proc sql;
create view have_v as
select
left.acc
, left.month as from_month
, right.month as to_month
, intck ('MONTH', left.month, right.month) as months_apart
from
have as left
join have as right on left.acc = right.acc
where
left.month < right.month
& left.default = 'N'
& right.default = 'D'
group by left.acc, left.month
having right.month = min(right.month)
order by
left.month, right.month
;
create table grid_bounds as
select
min(from_month) as min_from
, max(from_month) as max_from
, 1 as min_apart
, max(months_apart) as max_apart
from have_v
;
Объяснение SQL
Самостоятельное соединение - это соединение таблицы с самим собой.
have as left join have as right
Ограничение объединения ограничивает месячные комбинации from/to
только теми, которые находятся в одной учетной записи
on left.acc = right.acc
Ограничение where дополнительно ограничивает комбинации from/to
только теми, которые имеют to
в будущем и имеют желаемый default
переход
.
where
left.month < right.month
& left.default = 'N'
& right.default = 'D'
Оператор group by
и функция автоматического повторного предложения в предложении SAS Proc SQL
having
позволяют с помощью простого оператора выбрать самый ранний to
для данного from
group by left.acc, left.month
having right.month = min(right.month)
Для выбранных строк объединения месяцы могут быть вычислены с использованием функции данных SAS INTCK
(я думаю, что имя функции является аббревиатурой для фразы "INTerval Count of the kind вида")
, intck ('MONTH', left.month, right.month) as months_apart
Конкретное решение может использовать массив, если известен самый большой размер группы apriori.
Таблица для вывода
Некоторые месяцы могут отсутствовать из-за отсутствия переходов. Кроме того, некоторые пробелы также могут отсутствовать. В этих случаях не будет строк в have_v
. Чтобы получить полное покрытие для отчета, все возможные пересечения (или комбинации) создаются для использования в Proc TABULATE
proc sql;
create table grid_bounds as
select
min(from_month) as min_from
, max(from_month) as max_from
, 1 as min_apart
, max(months_apart) as max_apart
from have_v
;
quit;
data grid (label="All crossings to be shown in the output");
set grid_bounds;
do from_month = min_from to max_from;
do months_apart = 1 to max(12,max_apart);
OUTPUT;
end;
end;
keep from_month months_apart;
format from_month yymon.;
run;
Выводит отчет сетки с частотами разрыва для каждого из_месяц
options missing = '0' nocenter;
title "Account frequency";
title2 "Gap of month default changing from N to D";
proc tabulate data=have_v classdata=grid;
class from_month months_apart;
table
from_month=''
, months_apart * N=''
;
run;
options missing = '.';