#sql #sas
#sql #sas
Вопрос:
У меня есть этот макрос. Цель состоит в том, чтобы взять имя переменных из таблицы dicofr и поместить строки внутри в имя переменной, используя symput.
Однако что-то работает неправильно, потому что эта переменная amp;nvarname не рассматривается как переменная.
Это содержимое dicoamp;amp;paysamp;l
varname descr
var12 aza
var55 ghj
var74 mcy
Это содержимое dicoamp;amp;paysamp;l..1
varname
var12
var55
var74
Ниже приведен мой код
%macro testmac;
%let pays1=FR ;
%do l=1 %to 1 ;
data dicoamp;amp;paysamp;l..1 ; set dicoamp;amp;paysamp;l (keep=varname);
call symput("nvarname",trim(left(_n_))) ;
run ;
data aamp;amp;paysamp;l;
set aamp;amp;paysamp;l;
nouv_date=mdy(substr(date,6,2),01,substr(date,1,4));
format nouv_date monyy5.;
run;
proc sql;
create table toto
(nouv_date date , nomvar varchar (12));
quit;
proc sql;
insert into toto SELECT max(nouv_date),"amp;nvarname" as nouv_date as varname FROM aamp;amp;paysamp;l WHERE (amp;nvarname ne .);
%end;
%mend;
%testmac;
Дополнительный вопрос. Возможно ли, чтобы имя переменной и дата, связанные с этим именем переменной, были включены в переменную макроса? Мой человек-а рассказал мне об этом, но я никогда раньше этого не делал.
Заранее спасибо.
Отредактировано: у меня есть эта таблица
date col1 col2 col3 ... colx
1999M12 . . . .
1999M11 . 2 . .
1999M10 1 3 . 3
1999M9 0.2 3 2 1
Я пытаюсь узнать имя столбца с максимальной датой, зная, что значение внутри столбца отличается от пропущенного значения.
Для col1 это будет 1999M10. Для col2 это будет 1999M11 и т. Д…
Комментарии:
1. Вы
as
ошибаетесь. Вероятно, вы также хотите создать amp;nvarname по-другому, но, вероятно, это нормально. Я думаю, что вся эта процедура ошибочна; но я не совсем понимаю, что вы делаете. Скорее всего, вы можете сделать все это в datastep или аналогичном, не беспокоя средство макроса.2. Было бы полезно, если бы вы могли опубликовать пример сортировки выходного набора данных, который вы пытаетесь создать.
3. Привет, пожалуйста, найдите мое объяснение в отредактированной части. Спасибо. Дайте мне знать, если что-то неясно.
Ответ №1:
Основываясь на вашем обновлении, я думаю, что следующий код делает то, что вы хотите. Если вы не возражаете сначала отсортировать свой входной набор данных, вы можете получить все искомые значения за один шаг обработки данных — макросы не требуются!
data have;
length date $7;
input date col1 col2 col3;
format date2 monyy5.;
date2 = mdy(substr(date,6,2),1,substr(date,1,4));
datalines;
1999M12 . . .
1999M11 . 2 .
1999M10 1 3 .
1999M09 0.2 3 2
;
run;
/*Required for the following data step to work*/
/*Doing it this way allows us to potentially skip reading most of the input data set*/
proc sort data = have;
by descending date2;
run;
data want(keep = max_date:);
array max_dates{*} max_date1-max_date3;
array cols{*} col1-col3;
format max_date: monyy5.;
do until(eof); /*Begin DOW loop*/
set have end = eof;
/*Check to see if we've found the max date for each col yet.*/
/*Save the date for that col if applicable*/
j = 0;
do i = 1 to dim(cols);
if missing(max_dates[i]) and not(missing(cols[i])) then max_dates[i] = date2;
j missing(max_dates[i]);
end;
/*Use j to count how many cols we still need dates for.*/
/* If we've got a full set, we can skip reading the rest of the data set*/
if j = 0 then do;
output;
stop;
end;
end; /*End DOW loop*/
run;
РЕДАКТИРОВАТЬ: если вы хотите вывести имена вместе с максимальной датой для каждого, это можно сделать с небольшими изменениями:
data want(keep = col_name max_date);
array max_dates{*} max_date1-max_date3;
array cols{*} col1-col3;
format max_date monyy5.;
do until(eof); /*Begin DOW loop*/
set have end = eof;
/*Check to see if we've found the max date for each col yet.*/
/*If not then save date from current row for that col*/
j = 0;
do i = 1 to dim(cols);
if missing(max_dates[i]) and not(missing(cols[i])) then max_dates[i] = date2;
j missing(max_dates[i]);
end;
/*Use j to count how many cols we still need dates for.*/
/* If we've got a full set, we can skip reading the rest of the data set*/
if j = 0 or eof then do;
do i = 1 to dim(cols);
col_name = vname(cols[i]);
max_date = max_dates[i];
output;
end;
stop;
end;
end; /*End DOW loop*/
run;
Комментарии:
1. Привет, спасибо за это. Однако мне было интересно, можно ли также получить имя столбца. И если да, как бы вы это сделали?
2. Еще один вопрос, потому что мне любопытно, а также потому, что я только что обнаружил это, неожиданно, в одной из моих таблиц. Как бы вы поступили, если бы имя столбца не было последовательным, например, col1 col5 col7 col11 col12 и т. Д… Спасибо за ваше время.
3. max_date1 содержит максимальную дату с не пропускаемым значением для col1 и так далее, поэтому сопоставить имена довольно легко. Если у вас есть другие переменные с непоследовательными именами, просто перечислите их все в инструкции массива cols и убедитесь, что у вас одинаковое количество переменных в массиве max_dates.
Ответ №2:
Мне кажется, что вы пытаетесь использовать макросы для генерации INSERT INTO
инструкций для заполнения вашей таблицы. Это можно сделать вообще без использования макросов, что я бы рекомендовал.
Вы можете использовать инструкцию datastep для записи INSERT INTO
инструкций в файл. Затем, следуя datastep, используйте %include
инструкцию для запуска файла.
Это будет проще писать / поддерживать / отлаживать, а также будет работать лучше.