Sas 使用函数将值放入文件,而不创建新变量

Sas 使用函数将值放入文件,而不创建新变量,sas,Sas,我正在处理一个数据集,其内容我事先不知道。我的目标SAS实例是9.3,我不能使用SQL,因为它具有某些“保留”名称,例如不能用作列名的用户 谜题如下所示: data _null_; set some.dataset; file somefile; /* no problem can even apply formats */ put name age; /* how to do this without making new vars? */ put somefunc

我正在处理一个数据集,其内容我事先不知道。我的目标SAS实例是9.3,我不能使用SQL,因为它具有某些“保留”名称,例如不能用作列名的用户

谜题如下所示:

data _null_;

  set some.dataset;  file somefile;

  /* no problem can even apply formats */
  put name age;

  /* how to do this without making new vars? */
  put somefunc(name) max(age);

run;
%macro get_low_collision_varname(iSeed=);
  %local try cnt result;  
  %let cnt = 0;
  %let result = ;
  %do %while ("&result" eq "");
    %let try = %sysfunc(md5(&iSeed&cnt),hex32.);
    %if %sysfunc(anyalpha(%substr(&try,1,1))) gt 0 %then %do;
      %let result = &try;
    %end;
    %let cnt = %eval(&cnt + 1);
  %end;  
  &result
%mend;
我不能把var1=somefuncname;放置var1;因为这可能与名为var1的源变量冲突

我猜答案是制作一些宏函数来读取数据集标题,并返回一个安全的非冲突变量,或一个格式为fcmp的函数,但我想我会与社区一起检查,看看是否有一些老派的方法可以直接从函数输出,在数据步骤中?

PUT语句不接受函数调用作为输出的有效项

数据步骤不会像您在maxage中指出的那样使用列函数,因此在PUT中使用此类函数的可能性更小-

避免名称冲突

我的建议是使用一个不太可能发生冲突的变量名

_temp_001 = somefunc(<var>);
_temp_002 = somefunc2(<var2>);
put _temp_001 _temp_002;

drop _temp_:;

重新调整用途

您可以重新使用对正在运行的步骤不重要的任何自动变量。一些无所不在的候选人包括:

数字变量: _n_ _iorc_ _线状_ _n读_ 第一只在第一次之后调整。与BY语句关联的逻辑 最后的 字符变量: _infle_uu需要一个空的数据线; _主机名_ 避免 _文件_ _错误_ PUT语句不接受函数调用作为输出的有效项

数据步骤不会像您在maxage中指出的那样使用列函数,因此在PUT中使用此类函数的可能性更小-

避免名称冲突

我的建议是使用一个不太可能发生冲突的变量名

_temp_001 = somefunc(<var>);
_temp_002 = somefunc2(<var2>);
put _temp_001 _temp_002;

drop _temp_:;

重新调整用途

您可以重新使用对正在运行的步骤不重要的任何自动变量。一些无所不在的候选人包括:

数字变量: _n_ _iorc_ _线状_ _n读_ 第一只在第一次之后调整。与BY语句关联的逻辑 最后的 字符变量: _infle_uu需要一个空的数据线; _主机名_ 避免 _文件_ _错误_ 临时阵列

34         data _null_;
35            set sashelp.class;
36            array _n[*] _numeric_;
37            array _f[3] _temporary_;
38            put _n_ @;
39            do _n_ = 1 to dim(_f);
40               _f[_n_] = log(_n[_n_]);
41               put _f[_n_]= @;
42               end;
43            put ;
44            run;

1 _f[1]=2.6390573296 _f[2]=4.2341065046 _f[3]=4.7229532216
2 _f[1]=2.5649493575 _f[2]=4.0342406382 _f[3]=4.4308167988
3 _f[1]=2.5649493575 _f[2]=4.1789920363 _f[3]=4.5849674787
4 _f[1]=2.6390573296 _f[2]=4.1399550735 _f[3]=4.6298627986
5 _f[1]=2.6390573296 _f[2]=4.1510399059 _f[3]=4.6298627986
6 _f[1]=2.4849066498 _f[2]=4.0483006237 _f[3]=4.4188406078
7 _f[1]=2.4849066498 _f[2]=4.091005661 _f[3]=4.4367515344
8 _f[1]=2.7080502011 _f[2]=4.1351665567 _f[3]=4.7229532216
9 _f[1]=2.5649493575 _f[2]=4.1351665567 _f[3]=4.4308167988
临时阵列

34         data _null_;
35            set sashelp.class;
36            array _n[*] _numeric_;
37            array _f[3] _temporary_;
38            put _n_ @;
39            do _n_ = 1 to dim(_f);
40               _f[_n_] = log(_n[_n_]);
41               put _f[_n_]= @;
42               end;
43            put ;
44            run;

1 _f[1]=2.6390573296 _f[2]=4.2341065046 _f[3]=4.7229532216
2 _f[1]=2.5649493575 _f[2]=4.0342406382 _f[3]=4.4308167988
3 _f[1]=2.5649493575 _f[2]=4.1789920363 _f[3]=4.5849674787
4 _f[1]=2.6390573296 _f[2]=4.1399550735 _f[3]=4.6298627986
5 _f[1]=2.6390573296 _f[2]=4.1510399059 _f[3]=4.6298627986
6 _f[1]=2.4849066498 _f[2]=4.0483006237 _f[3]=4.4188406078
7 _f[1]=2.4849066498 _f[2]=4.091005661 _f[3]=4.4367515344
8 _f[1]=2.7080502011 _f[2]=4.1351665567 _f[3]=4.7229532216
9 _f[1]=2.5649493575 _f[2]=4.1351665567 _f[3]=4.4308167988

我认为你会很安全地选择一些不太可能冲突的名字。生成这些变量并使代码具有一定可读性的一种简单方法是只对字符串进行散列以创建有效的SAS varname,并使用宏引用使代码可读。大概是这样的:

data _null_;

  set some.dataset;  file somefile;

  /* no problem can even apply formats */
  put name age;

  /* how to do this without making new vars? */
  put somefunc(name) max(age);

run;
%macro get_low_collision_varname(iSeed=);
  %local try cnt result;  
  %let cnt = 0;
  %let result = ;
  %do %while ("&result" eq "");
    %let try = %sysfunc(md5(&iSeed&cnt),hex32.);
    %if %sysfunc(anyalpha(%substr(&try,1,1))) gt 0 %then %do;
      %let result = &try;
    %end;
    %let cnt = %eval(&cnt + 1);
  %end;  
  &result
%mend;
上面的代码接受一个种子字符串,并在其末尾添加一个数字。它迭代该数字,直到从md5函数获得有效的SAS varname作为输出。您甚至可以测试目标数据集名称,以确保变量不存在。如果它确实将该逻辑构建到上述函数中

测试它:

%let my_var = %get_low_collision_varname(iSeed=this shouldnt collide);    
%put &my_var;

data _null_;
  set sashelp.class;
  &my_var = 1;
  put _all_;
run;
结果:

Name=Alfred Sex=M Age=14 Height=69 Weight=112.5 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=1
Name=Alice Sex=F Age=13 Height=56.5 Weight=84 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=2

这并没有明确回答如何在不创建新变量名的情况下实现它的问题,但它确实提供了一个实际的解决方法。

我认为选择一些不太可能冲突的名称是非常安全的。生成这些变量并使代码具有一定可读性的一种简单方法是只对字符串进行散列以创建有效的SAS varname,并使用宏引用使代码可读。大概是这样的:

data _null_;

  set some.dataset;  file somefile;

  /* no problem can even apply formats */
  put name age;

  /* how to do this without making new vars? */
  put somefunc(name) max(age);

run;
%macro get_low_collision_varname(iSeed=);
  %local try cnt result;  
  %let cnt = 0;
  %let result = ;
  %do %while ("&result" eq "");
    %let try = %sysfunc(md5(&iSeed&cnt),hex32.);
    %if %sysfunc(anyalpha(%substr(&try,1,1))) gt 0 %then %do;
      %let result = &try;
    %end;
    %let cnt = %eval(&cnt + 1);
  %end;  
  &result
%mend;
上面的代码接受一个种子字符串,并在其末尾添加一个数字。它迭代该数字,直到从md5函数获得有效的SAS varname作为输出。您甚至可以测试目标数据集名称,以确保变量不存在。如果它确实将该逻辑构建到上述函数中

测试它:

%let my_var = %get_low_collision_varname(iSeed=this shouldnt collide);    
%put &my_var;

data _null_;
  set sashelp.class;
  &my_var = 1;
  put _all_;
run;
结果:

Name=Alfred Sex=M Age=14 Height=69 Weight=112.5 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=1
Name=Alice Sex=F Age=13 Height=56.5 Weight=84 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=2

这并没有明确回答如何在不创建新变量名的情况下实现它的问题,但它确实提供了一个实际的解决方法。

SAS和PROC SQL允许您使用任何有效的名称。在SQL中,您可能需要使用name literal'user'n,或者设置DQUOTE=ANSI选项并使用user.by-jove-可怕的name literals'n可能就是答案,只需在源代码上强制执行validvarname=v7,即可-“作业已完成”n?友好提示也可以使用NLITERAL函数将名称格式化为正确的格式。请注意,NLITERAL不会将用户转换为“USER”n,因为它不是SAS的无效名称。问题是它是SQL.SAS中的保留字,PROC SQL允许您使用任何有效名称。在SQL中,您可能需要使用name literal'user'n,或者设置DQUOTE=ANSI选项并使用user.by-jove-可怕的name literals'n可能就是答案,只需在源代码上强制执行validvarname=v7,即可-“作业已完成”n?友好提示也可以使用NLITERAL函数将名称格式化为正确的格式。请注意,NLITERAL不会将用户转换为“USER”n,因为它不是SAS的无效名称。问题是,它是SQL中的保留字。我喜欢这种方法,公平地说,那里的冲突不太可能发生。我喜欢这种方法,公平地说,那里的冲突将是som
这不太可能。我想用这种方法。但是碰撞的风险是一样的,不是吗?有数据_n1='42'_n2=42_f1='Thisttoo';跑没有新的变量名。唯一的冲突风险是临时数组名和一个变量名之间的冲突。选择一个不太可能的数组名就足够了,冲突将被记录为错误,这是一件好事是的,你是对的,我的问题措辞很糟糕,我不想要新变量名的原因是为了避免与现有变量发生冲突的风险。这确实回答了标题中所述的问题。我想使用这种方法。但是碰撞的风险是一样的,不是吗?有数据_n1='42'_n2=42_f1='Thisttoo';跑没有新的变量名。唯一的冲突风险是临时数组名和一个变量名之间的冲突。选择一个不太可能的数组名就足够了,冲突将被记录为错误,这是一件好事是的,你是对的,我的问题措辞很糟糕,我不想要新变量名的原因是为了避免与现有变量发生冲突的风险。这确实回答了标题中所述的问题