SAS:自动创建完整性约束

时间:2017-08-01 18:38:06

标签: database sas relational-database sas-macro

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

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. 列中的实际变量名称
  4. 运行通用proc数据集,例如:

        proc datasets nolist;
            modify &my_ds;
                ic create &my_clause
                    message = &my_msg;
        quit;
    
  5. 遍历所有行
  6. 任何人都可以帮我这个代码吗?我不知道我建议的步骤是否是实施我想要做的事情的最佳方式。基本上我试图在SAS中模拟关系数据库,并尽可能地自动化事物。

    谢谢!

3 个答案:

答案 0 :(得分:0)

您可以使用数据变量本身按照建议编写宏语句。你基本上想要创建一个新的long变量,这是一个宏调用看起来像是通过将所有变量串联在一起的每一行的datastep中编写的。您可以使用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.; 。以下应该有效:

cryptominisat --hhelp

答案 1 :(得分:0)

您可以使用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将通过插入变量值(proc datasetsds_name等等来执行相应的var_name正确的地方。 tranwrd函数会将[{1}}占位符替换为$var$的实际值。

答案 2 :(得分:0)

您可能会发现无法将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;