Sql SAS向存储在宏变量中的时间戳添加分钟数

Sql SAS向存储在宏变量中的时间戳添加分钟数,sql,sql-server,sas,sas-macro,Sql,Sql Server,Sas,Sas Macro,我通过SAS从SQL Server中提取大量数据。我希望使用循环每次提取一分钟(或一小时)的数据 时间戳的格式为“yyyymmdd hh:mm:ss.000” 通常,我会做以下事情: %macro Loop(num_days, tmstmp_begin): %do i = 0 to &num_days.; proc sql; ... where tmstmp between &tmstmp_begin + &i minutes and &t

我通过SAS从SQL Server中提取大量数据。我希望使用循环每次提取一分钟(或一小时)的数据

时间戳的格式为“yyyymmdd hh:mm:ss.000”

通常,我会做以下事情:

%macro Loop(num_days, tmstmp_begin):
%do i = 0 to &num_days.;
    proc sql;
    ...
    where tmstmp between &tmstmp_begin + &i minutes and &tmstmp_begin (&i+1) minutes;
    quit;
%end
%mend;
但服务器上不支持分钟添加。在Teradata中,我可以使用:

DATEADD(minute, 1, tmsmtmp)
要向时间戳添加分钟,但这不会在SAS中执行(它不会传递到服务器?):

无论如何,我想知道是否有一个整洁的
%sysfunc
解决方案可以帮助我避免生成一个SAS时间戳表,从中我可以读入宏变量,或者其他同样愚蠢的东西

基本上,我需要从:

%let i = 1;
%let tmstmp = '20150801 00:00:00.000'
致:


谢谢

我发现处理这些场景的最佳方法是使用自定义日期时间格式。您可以找到有关构建它们的链接。我建议将格式保存到公共库中,以便SAS会话始终可以使用该格式。格式为:

proc format ;
  picture mssqldt low-high = '''%Y-%0m-%0d %0H:%0M:%0S.000''' (datatype = datetime) ;
run ;
这将采用常规SAS日期时间戳,并按如下方式格式化(包括引号):

将此合并到SAS代码中的最佳方法是始终将日期和日期时间保留在其SAS表示形式中,并为SQL server格式的变量使用单独的变量。例如

计算要使用的日期时间:

%let my_datetime = %sysfunc(datetime());
使用SQL server格式的日期时间戳创建两个新变量。我总是叫我的
&sql\u start
&sql\u end
,这样他们读起来很好,我就不用想了

%let sql_start = %sysfunc(sum(&my_datetime),mssqldt.);
%let sql_end   = %sysfunc(intnx(minute,&my_datetime,1),mssqldt.);
您可以看到,为了计算
sql\u start
,我使用了
%sysfunc()
中的
sum()
函数,并传入了SAS datetime变量。我这样做是因为它不会更改日期时间的值,并允许我使用
%sysfunc()
的第二个参数,该参数将指定的格式应用于要返回的值

对于
sql\u end
我像往常一样使用了
intnx()
函数,并再次使用第二个
%sysfunc()
参数对其进行格式化

让我们打印这些值以查看它们的外观:

%put &sql_start &sql_end;
给出:

'2015-09-21 15:04:16.000' '2015-09-21 15:05:00'
那么,这只是在代码中使用它的一种情况,如下所示:

proc sql;
   ...
   where tmstmp between &sql_start and &sql_end;
quit;

下面是一个点中的所有代码(假设您已经定义了格式):


现在,如果您想一次提取一部分数据,可以将其全部编译成如下循环:

%macro get_data(iStart=,iEnd=);

  %local tmp_start tmp_end sql_start sql_end;

  %let tmp_start = &iStart;

  %do %while(&tmp_start le &iEnd);

    %let tmp_end = %sysfunc(intnx(hour,&tmp_start,0,end));

    /* MAKE SURE END OF LOOP ISNT GREATER THAN END DATETIME */
    %if &tmp_end > &iEnd %then %do;
      %let tmp_end = &iEnd;
    %end;


    %let sql_start = %sysfunc(sum(&tmp_start),mssqldt.);
    %let sql_end   = %sysfunc(sum(&tmp_end  ),mssqldt.);

    /* DO SQL HERE */
    %put &sql_start &sql_end;

    /* INCREMENT THE LOOP */
    %let tmp_start = %sysfunc(intnx(hour,&tmp_start,1,beginning));

  %end;

%mend;
从今天到明天的某个时间:

%get_data(iStart=%sysfunc(datetime()),
          iEnd  =%sysfunc(dhms(%sysfunc(date())+1,2,30,13))
         );
产生的运行时间如下:

'2015-09-21 15:25:33.000' '2015-09-21 15:59:59.000'
'2015-09-21 16:00:00.000' '2015-09-21 16:59:59.000'
'2015-09-21 17:00:00.000' '2015-09-21 17:59:59.000'
'2015-09-21 18:00:00.000' '2015-09-21 18:59:59.000'
'2015-09-21 19:00:00.000' '2015-09-21 19:59:59.000'
'2015-09-21 20:00:00.000' '2015-09-21 20:59:59.000'
'2015-09-21 21:00:00.000' '2015-09-21 21:59:59.000'
'2015-09-21 22:00:00.000' '2015-09-21 22:59:59.000'
'2015-09-21 23:00:00.000' '2015-09-21 23:59:59.000'
'2015-09-22 00:00:00.000' '2015-09-22 00:59:59.000'
'2015-09-22 01:00:00.000' '2015-09-22 01:59:59.000'
'2015-09-22 02:00:00.000' '2015-09-22 02:30:13.000'

SAS将日期时间存储为秒数,因此您可以尝试添加&i minutes*60秒/分钟以获得有效的间隔,而不是添加一分钟

where tmstmp between "&tmstmp_begin"dt + &i*60 and "&tmstmp_begin"dt + (&i+1)*60;

编辑:如果您有一个字符变量,但只有当您使用的是实际的SAS日期时间值时,这将不起作用

回答得很好,罗伯特-正是我想要的。感谢您花时间写下如此详细的内容。感谢您的回答Reeza,但是我的问题是我无法添加到&tmsp_begin(有或没有分钟);我认为这是因为它在sql表中存储为字符串。通常datetime戳是日期时间,但宏变量是字符,我稍微修改了答案,但@Robert的答案可能更可取。不过,我认为上述方法也应该有效。
%macro get_data(iStart=,iEnd=);

  %local tmp_start tmp_end sql_start sql_end;

  %let tmp_start = &iStart;

  %do %while(&tmp_start le &iEnd);

    %let tmp_end = %sysfunc(intnx(hour,&tmp_start,0,end));

    /* MAKE SURE END OF LOOP ISNT GREATER THAN END DATETIME */
    %if &tmp_end > &iEnd %then %do;
      %let tmp_end = &iEnd;
    %end;


    %let sql_start = %sysfunc(sum(&tmp_start),mssqldt.);
    %let sql_end   = %sysfunc(sum(&tmp_end  ),mssqldt.);

    /* DO SQL HERE */
    %put &sql_start &sql_end;

    /* INCREMENT THE LOOP */
    %let tmp_start = %sysfunc(intnx(hour,&tmp_start,1,beginning));

  %end;

%mend;
%get_data(iStart=%sysfunc(datetime()),
          iEnd  =%sysfunc(dhms(%sysfunc(date())+1,2,30,13))
         );
'2015-09-21 15:25:33.000' '2015-09-21 15:59:59.000'
'2015-09-21 16:00:00.000' '2015-09-21 16:59:59.000'
'2015-09-21 17:00:00.000' '2015-09-21 17:59:59.000'
'2015-09-21 18:00:00.000' '2015-09-21 18:59:59.000'
'2015-09-21 19:00:00.000' '2015-09-21 19:59:59.000'
'2015-09-21 20:00:00.000' '2015-09-21 20:59:59.000'
'2015-09-21 21:00:00.000' '2015-09-21 21:59:59.000'
'2015-09-21 22:00:00.000' '2015-09-21 22:59:59.000'
'2015-09-21 23:00:00.000' '2015-09-21 23:59:59.000'
'2015-09-22 00:00:00.000' '2015-09-22 00:59:59.000'
'2015-09-22 01:00:00.000' '2015-09-22 01:59:59.000'
'2015-09-22 02:00:00.000' '2015-09-22 02:30:13.000'
where tmstmp between "&tmstmp_begin"dt + &i*60 and "&tmstmp_begin"dt + (&i+1)*60;