SAS 直通查询使用硬编码日期运行,但不使用宏变量作为日期

SAS Passthrough Query Runs With Hard Coded Dates, but not Macro Variables as Dates

我有一个脚本 运行 是一个连接到 Oracle 数据库的 SAS passthrough 查询。这是 运行 在 Unix 服务器上的 cronjob 的一部分,多年来一直没有问题。然而,在过去的几周里,这项工作已经开始在这一特定步骤上挂起 - 根据日志,它过去需要大约 15 秒才能 运行 但现在只会 运行 无限期地结束之前工作。日志中没有相关的错误或警告 - 该作业将创建一个锁定文件,并且 运行 无限期地创建,直到我们必须终止它。

作业挂掉的步骤贴在下面。有两个宏变量 &start_dt 和 &end_dt,它们表示 运行ge 作业提取销售数据的日期。

在调查过程中,我们尝试了几种不同的方法,通过改变三件事,能够在通常的时间内成功地完成这一步 运行:

  • 运行通过企业指南客户端连接脚本 到同一台服务器,而不是通过 CLI / shell 运行ning 脚本 脚本

  • 将步骤写入的库改为工作而不是写入
    数据集到 salesdata 库(如下面的代码所示)

  • 将日期更改为硬编码值而不是宏变量。

至于日期变量本身,它们是date9格式的字符串,例如 &start_dt = '22 年 5 月 8 日',&end_dt = '22 年 5 月 14 日'。最初我怀疑这个问题与日期的结构方式有关,因为这是我继承的一个较旧的项目,但我很困惑为什么这份工作 运行 这么长时间都没有问题,直到几周前,即使这些格式奇怪的日期宏变量。

我考虑的另一种可能性是,当执行到这一步时,unix 服务器上的某种资源被锁定,可能是由于某种挂起的作业或与旧文件(如日志)的其他一些冲突或以前的 sas 数据集。

下面粘贴的脚本中步骤的问题版本:

PROC SQL;
connect to oracle(user=&uid pass=&pwd path='@dw');

create table salesdata.shipped as

    Select
      SKN_NBR,
      COLOR_NBR,
      SIZE_NBR,
      SALESDIV_KEY,
      ORDER_LINE_QTY as QUANTITY label="SUM(ORDER_LINE_QTY)",
      EX1 as DOLLARS label="SUM(EX1)" from connection to oracle(

      select
        A1."SKN_NBR",
        A1."COLOR_NBR",
        A1."SIZE_NBR",
        decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
                                  'IQ ', 'IQ',
                                  'IQC', 'IQ',
                                  'ISQ', 'IQ',
                                  'IWC', 'IQ',
                                        'QVC'),
        SUM(A1."ORDER_LINE_QTY"),
        SUM(A1."ORDER_LINE_QTY" * A1."ORDER_LINE_PRICE_AMT")

      from DW.ORDERLINE A1, DISTINCT_SKN A2, DW.ORDERSTATUSTYPE A3

      where
        A2."SKN_NBR" = A1."SKN_NBR" AND
        A1."CURRENT_STATUS_DATE" Between &start_dt and &end_dt AND
        A1."ORDERLINESTATUS_KEY" = A3."ORDERLINESTATUS_KEY" AND
        A3."ORDERSTATUS_SHIPPED" = 'Y' AND
        A1."ORDER_LINE_PRICE_AMT" > 0

      group by A1."SKN_NBR",
               A1."COLOR_NBR",
               A1."SIZE_NBR",
               decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
                                         'IQ ', 'IQ',
                                         'IQC', 'IQ',
                                         'ISQ', 'IQ',
                                         'IWC', 'IQ',
                                         'QVC')

      order by A1."SKN_NBR",
               A1."COLOR_NBR",
               A1."SIZE_NBR",
               decode(A1."SALESDIV_KEY", 'ILB', 'IQ',
                                         'IQ ', 'IQ',
                                         'IQC', 'IQ',
                                         'ISQ', 'IQ',
                                         'IWC', 'IQ',
                                         'QVC')

) as t1(SKN_NBR, COLOR_NBR, SIZE_NBR, SALESDIV_KEY, ORDER_LINE_QTY, EX1)
;
disconnect from oracle; quit;


  [1]: https://i.stack.imgur.com/GGjin.jpg

您需要为 Oracle 中的日期常量使用什么样式取决于您在 Oracle 中的设置。但通常你可以使用像下面这样的表达式

date '2022-05-14' 
'2022-05-14'

您似乎声称在您的系统上您可以使用像

这样的值
'14-May-22'

(Oracle 怎么知道你指的是哪个世纪?)。

请注意,在 Oracle 中,在常量周围使用单引号很重要,因为它将双引号中的字符串解释为对象名称。

因此,如果您在 SAS 中有日期值,只需确保使宏变量值看起来像 Oracle 想要的那样。

例如,要将 ENDDT 设置为今天的日期,您可以使用:

data _null_;
  call symputx('enddt',quote(put(today(),date11.),"'"));
run;

这与

相同
%let enddt='17-MAY-2022';

所以@Tom 的回答很有帮助——我们的 DBA 似乎在几周前更新了一些设置,这影响了 Oracle 在接受哪些日期格式方面的严格程度。

就其价值而言,日期宏变量是使用读取日期键数据集的笨重数据步骤动态构建的:

您会注意到为 bost 变量放在一起的日期字符串的最后一段使用 year2。格式,所以只有年份的最后两位数字。

就@Tom 的观点而言,这显然让 Oracle 混淆了它属于哪个世纪,因此工作被挂断了。

data dateparm;
  set salesdata.week_end_date;

  start = "'" || put(day(week_end_date - 6), z2.) || '-' || put(week_end_date - 6, monname3.) || '-' ||
                 put(week_end_date - 6, year2.) || "'";

  end = "'" || put(day(week_end_date), z2.) || '-' || put(week_end_date, monname3.) || '-' ||
               put(week_end_date, year2.) || "'";


  call symput('start_dt', start);
  call symput('end_dt', end);

run;

一旦我将此步骤更改为使用 year4。最后一块的格式,这项工作能够 运行 在 unix 和 E 指南上顺利进行。示例如下:

data dateparm;
  set npdd.week_end_date;

  start = "'" || put(day(week_end_date - 6), z2.) || '-' || put(week_end_date - 6, monname3.) || '-' ||
                 put(week_end_date - 6, year4.) || "'";

  end = "'" || put(day(week_end_date), z2.) || '-' || put(week_end_date, monname3.) || '-' ||
               put(week_end_date, year4.) || "'";


  call symput('start_dt', start);
  call symput('end_dt', end);

run;