我正在尝试在数据步骤中运行insert语句来填充表。运行代码错误时出现以下错误:域错误。日志中没有关于此错误的其他信息。
我正在实施的示例代码是:
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是我在查询中使用的数据集中的值。
我不知道为什么会出现这种错误。最初,我认为可能是因为处理器工作太多,我通过使用睡眠和唤醒等待,但是,我仍然得到错误。另外,我总是不会得到这个错误。它有时会发生,有时也不会发生。
答案 0 :(得分:2)
我正在运行Joe的代码,我没有任何问题。这是在带有SAS 9.2m3的Windows 7上,因此可能与您的环境不同。此外,由于我没有你的数据,我无法复制你所做的事情。
我看到许多可能改进代码的东西,但错误消息表明SAS内部存在一些问题。我通常会发现使用SAS Tech支持更有效率,而不是推测黑盒子中可能发生的事情,称为SAS。提交此票。
我在SAS支持网站上对此错误消息做了很好的引用,指出了Oracle特定问题。 http://support.sas.com/kb/14/873.html
答案 1 :(得分:1)
首先,我尝试删除'PROC SQL;'和'退出;'从你重复的CALL EXECUTE开始,每次只运行一次 - 使用IF N = 1;运行PROC SQL,您可以使用LAST变量来确定何时调用QUIT,或者只是将其从datastep中删除并写入QUIT;运行后;数据步骤,然后在适当的地方执行。重复调用SQL环境可能会导致问题本身。
另一种可能的解决方案是使用CALL EXECUTE,将这些全部写入文本文件,然后%包含该文本文件。同样,%包括不包括PROC SQL和QUIT的部分,%include包含在PROC SQL块中。如果CALL EXECUTE在这里特别有问题,那么这就解决了这个问题,而且功能没有区别。老实说,我更喜欢这种方法,因为它更接近你正在做的事情(以编程方式编写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;
答案 2 :(得分:0)
我认为你的原因是因为call execute
的扩展问题。限制可以通过各种各样的事情来确定,例如可用内存量,指令队列的限制(我做了那个btw)等等。
在这种情况下,一个好的做法可能是使用数据集集合语句中的firstobs
和obs
选项以1000个批量处理调用。
DATA _NULL_;
SET DataSetA(firstobs=1 obs=1000);
*Call Execute ...;
run;
DATA _NULL_;
SET DataSetA(firstobs=1001 obs=2000);
*Call Execute ...;
run;
然后根据需要宏观上述代码...
答案 3 :(得分: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
)和外部文件的lineize的长度(默认为256)。
答案 4 :(得分: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();
答案 5 :(得分: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没有特殊错误消息的其他内容,但仍然违反了某些规则。无论如何,短语“域错误”可以这样解释。
答案 6 :(得分:0)
如果您拥有最新版本的SAS(版本9.3维护2),则可以尝试使用DOSUBL语句。它允许您在DATA步骤中运行任何SAS语句集合,只要这些语句代表“完整”步骤即可。即:全局语句,使用RUN的DATA步骤;使用RUN / QUIT的PROC步骤。
它被标记为实验,但this SAS Global Forum 2012 paper中提供了基本文档和示例。
注意:尽管DOSUBL最初是SAS 9.3中的有效语法,但我的经验是它使用SAS 9.3M2可以更好地工作。