макрос в таблицу или переменную макроса с помощью sas

#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 инструкцию для запуска файла.

Это будет проще писать / поддерживать / отлаживать, а также будет работать лучше.