2

我正在尝试在数据步骤中运行插入语句来填充表。运行代码 ERROR: Domain error 时出现以下错误。日志中没有关于此错误的其他信息。

我正在实现的示例代码是:

  DATA _NULL_;
  SET DataSetA;

 Call Execute ('Proc Sql; Insert Into TableA Select col1,col2,c.Col2 From Table B Inner        Join ( Select col1,' || Datasetcol1 || ' As col2, ' || Datasetcol2 || ' as Col3 FROM ' || Datasetcol3 || ' ) c On b.Col1=c.col1;quit;');

 run;

如果有 2000 条记录,此代码运行正常,但现在我有 10000 条记录并抛出该错误。Datasetcol1 和 Datasetcol2 是我在查询中使用的数据集的值。

我不知道为什么会发生此错误。最初,我认为这可能是因为处理器工作太多,我使用 sleep 和 wakeup 等待,但是,我仍然得到错误。另外,我并不总是收到此错误。它有时会发生,有时不会。

4

7 回答 7

2

我正在运行 Joe 的代码,我没有任何问题。这是在带有 SAS 9.2m3 的 Windows 7 上,因此可能与您的环境不同。另外,由于我没有您的数据,因此我无法复制您所做的事情。

我看到很多可能会改进代码的东西,但错误消息表明 SAS 内部存在一些问题。我通常发现与 SAS 技术支持人员核实比推测称为 SAS 的黑匣子中可能发生的事情更有效。提交一张票。

我在 SAS 支持站点上很好地引用了此错误消息,它指向 Oracle 特定问题。http://support.sas.com/kb/14/873.html

于 2012-10-18T20:50:57.097 回答
1

首先,我会尝试删除“PROC SQL;” 和“退出;” 从您重复的 CALL EXECUTE 中,并且每次只运行一次 - 使用 IF N = 1; 运行 PROC SQL,您可以使用 LAST 变量来确定何时调用 QUIT,或者将其留在数据步之外并编写 QUIT;运行后;数据步骤,因为它将在适当的位置执行。重复调用 SQL 环境可能会导致您的问题本身。

另一种可能的解决方案是不使用 CALL EXECUTE,而是将这些全部写入文本文件,然后 %include 该文本文件。同样,%include 不包括 PROC SQL 和 QUIT 的部分,以及 PROC SQL 块内的 %include。如果 CALL EXECUTE 在这里特别有问题,那么这在功能上没有区别。老实说,我还是更喜欢这种方法,因为它a)更接近你真正在做的事情(以编程方式编写SQL代码,然后执行它),b)更容易调试(它编写一个文本文件,然后你可以从中获取行去测试)。

编辑:从调用中删除 PROC SQL 和 QUIT 的示例:

data class;
set sashelp.class;
run;

filename _null dummy;
proc printto log=_null;
data _null_;
set sashelp.class end=eof;
if _n_ = 1 then call execute('PROC SQL;');
do _t = 1 to 10000;
  _exec = cats('insert into class (name,age,sex) select name,age,sex from sashelp.class where name="',name,'";');
  call execute(_exec);
end;

if eof then call execute('QUIT;');
run;
于 2012-10-17T06:44:43.507 回答
0

对于如此庞大的代码生成,更安全的方法是生成一个外部文件并运行它:

 DATA _NULL_;
  SET DataSetA;
  file "script.sas";
  length stmt $200;
  stmt = 'Proc Sql; Insert Into TableA Select col1,col2,col3 From Table B Inner        Join ( Select col1,' || Datasetcol1 || ' As col2, ' || Datasetcol2 || ' as Col3 FROM Table C) c On b.Col1=c.col1;quit;';
  put stmt;
 run;

 %include "script.sas" ;

这也为您提供了在处理代码时检查生成代码的地方。

注意:注意保存代码的变量的长度(stmt $200此处)和外部文件的行大小(默认为 256)。

于 2012-10-17T16:04:28.763 回答
0

您可以call execute通过宏工具执行所有操作来完全避免使用。

例子:

%macro InsertFromTable(table_name, ds_col1, ds_col2);
    proc sql;
        Insert Into TableA 
        Select col1,col2,col3 
        From Table B 
        Inner Join ( 
            Select col1
                ,&ds_col1. As col2
                ,&ds_col2. as Col3 
            FROM &table_name. as C
        ) c On b.Col1=c.col1
    ;quit;
%mend;


%Macro InsertFromAllTables();
    %let dsid=%sysfunc(open(DataSetA,i));
    %syscall set(dsid);

    %let rc = %sysfunc(fetch(&dsid));
       %do %while (&rc. eq 0);            
            %InsertFromTable(&table_name., &col1., &col2.);
            %let rc = %sysfunc(fetch(&dsid));            
       %end;
    %let rc=%sysfunc(close(&dsid));
%mend;


data DatasetA;
    infile datalines firstobs=3 missover;    
    input table_name: $10. col1: $10. col2: $10.;

    datalines;    
    table_name   col1   col2
    ----------   ----   ----
    Table_1       C1      C2
    Table_2       D1      D2
    Table_x       xx      yy
;run;



%InsertFromAllTables();
于 2012-10-17T21:11:48.640 回答
0

如果您拥有最新版本的 SAS(版本 9.3 Maint 2),您可以尝试使用 DOSUBL 语句。它允许您从 DATA 步骤中运行任何 SAS 语句集合,只要这些语句代表“完整”步骤。即:全局语句,DATA 步与 RUN;,PROC 步与 RUN/QUIT。

它被标记为实验性的,但基本文档和示例可在此 SAS 全球论坛 2012 论文中找到。

注意:尽管 DOSUBL 最初在 SAS 9.3 中是有效的语法,但我的经验是它在 SAS 9.3M2 中效果更好。

于 2012-10-19T18:12:37.857 回答
0

我将把它分成另一个答案,因为它与我最初的想法完全不同。

我首先假设这是一个数据错误。通过执行以下操作进行故障排除: 1. 使用前 5000 行。如果成功,则仅使用第二个 5000 行 (firstobs=5001)。如果两者都不失败,则不是数据错误;如果其中一个或两个都失败,则可能是数据错误。2. 然后执行二叉树搜索式算法。假设前 5000 个失败。然后尝试第一个 2500。如果失败,请尝试第一个 1250。继续直到找到通过的东西。然后尝试最后一个通过的另一半(例如,625 通过;所以尝试 626-1250)。

继续分成两半,直到您拥有可以检查的一小组数据(一行、五行,任何最适合您查看数据的能力,特别是基于内部连接创建的行数)。查看行,看看是否有任何可能非法的内容弹出。

当然,如果您达到特定大小(例如 625)并发现从 1 到 10000 的所有 625 集合都通过了,只是当组合成更大的集合时没有通过,您可能再次没有数据错误 - 但我认为这很可能你这样做,特别是考虑到拉里发布的链接。

如果您想要一个更快的解决方案,请考虑在 DatasetA 和 TableA/B 中对相关变量进行频率处理。看看其中一行中的任何内容是否非法或不寻常。例如,如果您看到一个不可能的日期,或者一个没有意义的负数,则可能是有问题。

最后,这个插入行的系统是什么?我希望不是 SAS(因为有很多更好的 SAS-sy 解决方案)。根据系统的不同,您可能违反了该系统的规则之一(例如在 Larry 的链接中),或者您可能违反了表约束或其他 SAS 没有特殊错误消息的东西,但仍然违反了一些规则。无论如何,“域错误”一词都可以这样理解。

于 2012-10-18T21:36:34.470 回答
0

我认为你是对的,原因是call execute. 限制可以由多种因素决定,例如可用内存的数量、指令队列的限制(顺便说一句,我做了这个)等等......

在这种情况下,一个好的做法可能是使用数据集集语句上的firstobsand选项以 1000 个批处理执行调用。obs

DATA _NULL_;
  SET DataSetA(firstobs=1 obs=1000);
  *Call Execute ...;
run;

DATA _NULL_;
  SET DataSetA(firstobs=1001 obs=2000);
  *Call Execute ...;
run;

然后根据需要对上述代码进行宏化...

于 2012-10-16T23:49:59.000 回答