繁体   English   中英

SAS:自动创建完整性约束

[英]SAS: Automating integrity constraints creation

我试图根据此数据集自动创建一些完整性约束:

ds_name | var_name | ic_clause                          | ic_msg
--------+----------+------------------------------------+-----------------------
tableA  | var1     | primary key($var$)                 | $var$ is a primary key
tableB  | var2     | check(where=($var$ in ('a', 'b'))) | invalid $var$ value

这个想法是创建一个遍历该数据集并相应地创建IC的通用程序。 在这种特定情况下,等效的硬编码程序将是:

proc datasets nolist;
    modify tableA;
        ic create primary key(var1)
            message = "var1 is a primary key";
quit;

proc datasets nolist;
    modify tableB;
        ic create check(where=(var2 in ('a', 'b')))
            message = "invalid var2 value";
quit;

这些是我在程序中想象的步骤,但是我需要帮助将它们转换为实际代码:

  1. 获取一行的值并将其放入宏变量
  2. $ var $子字符串替换 var_name列中的实际变量名称
  3. 运行通用的proc数据集,例如:

      proc datasets nolist; modify &my_ds; ic create &my_clause message = &my_msg; quit; 
  4. 遍历所有行

谁能帮我这个代码吗? 我不知道我建议的步骤是否是实现我要执行的操作的最佳方法。 基本上,我正在尝试在SAS中模拟关系数据库,并尽可能自动地执行操作。

谢谢!

您可以按照自己的建议使用数据变量本身来编写宏语句。 您基本上想创建一个新的长变量,通过将所有变量串在一起,宏调用看起来像在数据步骤中写成每一行一样。 您可以使用tranwrd函数将占位符文本替换为实际的VAR_NAME 下面应该工作:

data test;
    infile datalines dlm="|";
    length DS_NAME VAR_NAME IC_CLAUSE IC_MSG $50;
    input DS_NAME $ VAR_NAME $ IC_CLAUSE $ IC_MSG $;
    datalines;
    tableA  | var1     | primary key($var$)                 | $var$ is a primary key
    tableB  | var2     | check(where=($var$ in ('a', 'b'))) | invalid $var$ value
    ;
run;

** write your master macro **;
%MACRO master_loop(DS_NAME=,IC_CLAUSE=,IC_MSG=);
proc datasets nolist;
    modify &DS_NAME.;
        ic create &IC_CLAUSE.
            message = "&IC_MSG.";
quit;
%MEND;

** create all your macro statements **;
data master_strings; 
    length STR $200;
    set test;
    IC_CLAUSE1 = tranwrd(IC_CLAUSE,"$var$",strip(VAR_NAME)); /* replace the placeholder with the actual VAR_NAME contents */
    IC_MSG1 = tranwrd(IC_MSG,"$var$",strip(VAR_NAME)); /* replace the placeholder with the actual VAR_NAME contents */
    STR = %nrstr("%master_loop("||"DS_NAME="||strip(DS_NAME)||",IC_CLAUSE="||strip(IC_CLAUSE1)||",IC_MSG="||strip(IC_MSG1)||");");
run;

** put all macro statements into a list**;
** this would look similar to writing out multiple %master_loop statements if hard-coded **;
proc sql noprint;
    select STR
    into: all_macro_calls separated by " "
    from master_strings;
quit;

** submit all your macro calls **;
%put &all_macro_calls.;

您可以使用call execute来使您的“硬编码”程序完全动态(其中IC是具有约束的基本数据集):

data _null_;
set IC;
call execute("proc datasets nolist;modify "||strip(ds_name)
   ||";ic create "||tranwrd(strip(ic_clause),'$var$',strip(var_name))
   ||" message = '"||tranwrd(strip(ic_msg),'$var$',strip(var_name))
   ||"';quit;");
run;

基本上,对于数据集中的每个观察, call execute将通过在正确的位置插入变量值( ds_namevar_name等)来执行适当的proc datasets tranwrd函数将负责将$var$占位符替换为var_name的实际值。

您可能会发现您无法将SAS转换为DBMS。 最好使用元数据生成检查数据的程序,而不要尝试实施完整性约束。

但是数据驱动代码生成的概念很有趣,因此让我们看看是否可以使用您的示例来演示如何从元数据生成代码。 我发现当您将元数据中的变量名称与需要生成的代码进行匹配时,它会更好地工作。 因此,让我们在IC语句MESSAGE上调用用于创建MESSAGE=选项的变量。

现在,我们可以使用一个简单的数据步骤来生成代码。 不知道为什么在约束和消息字段中使用伪代码而不是仅对值进行硬编码,但是我们可以使用TRANWRD()函数用VARNAME变量的值替换$varname$字符串。

因此,让我们制作一个示例元数据文件。

data ic_metadata;
  infile datalines dlm="|";
  length libname $8 memname $32 varname $32 constraint message $200;
  input libname memname varname constraint message ;
datalines;
work|tableA|var1|primary key($varname$)                |$varname$ is a primary key
work|tableB|var2|check(where=($varname$ in ('a', 'b')))|invalid $varname$ value
;

以及一些示例数据。

data tablea tableb ;
 length var1 8 var2 $8 ;
 var1+1;
 var2='a';
run;

现在,让我们使用元数据生成代码,并使用%INCLUDE来运行它。

 filename code temp;
 data _null_;
   file code ;
   set ic_metadata ;
   by libname memname ;
   if first.libname then put 'proc datasets lib=' libname 'nolist;' ;
   if first.memname then put '  modify ' memname ';' ;
   constraint=tranwrd(constraint,'$varname$',trim(varname));
   message=tranwrd(message,'$varname$',trim(varname));
   put 'ic create ' constraint message= :$quote. ';' ;
   if last.memname then put 'run;';
   if last.libname then put 'quit;' ;
 run;
 %include code / source2 ;

因此,运行示例,我们将获得如下所示的SAS日志:

161  +proc datasets lib=work nolist;
162  +  modify tableA ;
163  +ic create primary key(var1) message="var1 is a primary key" ;
NOTE: Integrity constraint _PK0001_ defined.
164  +run;

NOTE: MODIFY was successful for WORK.TABLEA.DATA.
165  +  modify tableB ;
166  +ic create check(where=(var2 in ('a', 'b'))) message="invalid var2 value" ;
NOTE: Integrity constraint _CK0001_ defined.
167  +run;

NOTE: MODIFY was successful for WORK.TABLEB.DATA.
168  +quit;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM