我对SAS PROC SQL中的以下2个代码有疑问。

代码1 :(标准图书版本)

CREATE TABLE WORK.OUTPUT AS
SELECT
    "CLAIM" AS SOURCE,
    a.CLAIMID,
    a.DXCODE
FROM
    DW.CLAIMS_BAV AS a
WHERE
    a.SITEID = '0001'
    AND a.CLAIMID IN (SELECT CLAIMID FROM WORK.INPUT)

代码2 :(实践中更快的方法)
CREATE TABLE WORK.OUTPUT AS
SELECT
    "CLAIM" AS SOURCE,
    a.CLAIMID,
    a.DXCODE
FROM
    DW.CLAIMS_BAV AS a
WHERE
    a.SITEID = '0001'
    AND a.CLAIMID IN ('10001', '10002', '10003', ... '15000')

当我尝试通过在#1中使用子查询来更优雅地执行此操作时,运行时间会超过50分钟。但是使用代码2在3分钟内返回了相同的输入。为什么?注意,使用INNER JOIN(after reading this)也同样慢。输入的是5000+ CLAIMID,我每天手动将其粘贴到IN('...')块中。

PS:CLAIMID是虚构的,在现实生活中它们是随机的。

CLAIMID在DW.CLAIMS中建立索引。我正在使用SAS PROC SQL访问Oracle数据库。发生了什么,还有更好的方法吗?谢谢!

最佳答案

我不知道我能不能告诉您为什么SAS在初选时这么慢?在那种情况下,显然没有优化的地方。

如果我不得不猜测,我猜想SAS在第一种情况下决定不能使用直通SQL,因此它先下载整个大表,然后在SAS端运行,而在第二种情况下是将查询传递到SQL数据库,并且仅将结果行传输回去。

但是无论如何,有几种方法可以解决此问题。这是一个:使用宏变量精确地进行粘贴!

proc sql;
select quote(strip(claimid)) into :claimlist separated by ','
from work.input
;

CREATE TABLE WORK.OUTPUT AS
SELECT
    "CLAIM" AS SOURCE,
    a.CLAIMID,
    a.DXCODE
FROM
    DW.CLAIMS_BAV AS a
WHERE
    a.SITEID = '0001'
    AND a.CLAIMID IN (&claimlist.)
;
quit;

Tada,您不必再碰这个了,它与您执行的复制/粘贴相同。

一些额外的注释给出了一些评论:

如果CLAIMID小于15,则可能会有空格填充,因此我添加了strip来删除这些填充。字符串比较并不重要-除非您可能用尽了宏语言,否则我担心某些DBMS可能实际上关心填充。如果15是恒定长度,则可以省略strip

宏变量在空间上最多可运行64K。如果您有15个字符变量加上“”两个加逗号1,则您有18个字符;您可以容纳3500个以上的值。不幸的是,这个数字还不到5000。

在这种情况下,您可以将字段拆分为两个宏变量(希望很容易,请使用obsfirstobs),或者可以执行其他一些解决方案。
  • work.input数据集转移到DW libname中,然后在其中执行SQL连接。
  • 将ClaimID的内容放入文件中,而不是宏变量中,然后%include该文件。
  • 使用call execute执行整个proc SQL。

  • 这是CALL EXECUTE的一个示例。
    data _null_;
      set work.input end=eof;
      if _n_=1 then do;
        call execute('CREATE TABLE WORK.OUTPUT AS
    SELECT
        "CLAIM" AS SOURCE,
        a.CLAIMID,
        a.DXCODE
    FROM
        DW.CLAIMS_BAV AS a
    WHERE
        a.SITEID = "0001"
        AND a.CLAIMID IN (');      *the part of the SQL query before the list of IDs;
      end;
      call execute(quote(claimID) || ' ');
      if EOF then do;
        call execute('); QUIT;');  *the part of the SQL query after the list of IDs;
      end;
    run;
    

    实际上,这与%INCLUDE解决方案几乎完全相同,除了您将填充的put填充到文本文件中,而不是对其进行CALL EXECUTE编码之后,再对文本文件进行%INCLUDE

    关于sas - SAS PROC SQL:在对IN()进行硬编码时,为什么会有不同?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47099028/

    10-15 05:06