2015-09-21 2 views
3

Я извлекаю большой объем данных с SQL Server через SAS. Я хотел бы получить одну минуту (или час) данных за раз, используя цикл.SAS Добавление минут к отметке времени, хранящейся в переменной макроса

Формат метки времени: «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 (это через не передать на сервер?):

ERROR: Function DATEADD could not be located. 

Во всяком случае Мне было интересно, есть ли аккуратное решение %sysfunc, которое поможет мне избежать создания таблицы SAS временных меток, из которых я буду читать макропеременные, или что-то еще так же глупо.

В принципе мне нужно идти от:

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

к:

%put ...something involving tmstmp and i...; 
'20150801 00:01:00.000' 

Спасибо!

ответ

2

Лучший способ, которым я нашел для обработки этих сценариев, - использовать пользовательский формат даты и времени. Вы можете найти ссылку на их создание here. Я рекомендую сохранить формат в общей библиотеке, чтобы он всегда был доступен для ваших сеансов SAS. Формат будет:

proc format ; 
    picture mssqldt low-high = '''%Y-%0m-%0d %0H:%0M:%0S.000''' (datatype = datetime) ; 
run ; 

Это займет регулярный SAS DATETIME штамп и отформатировать его, как это (включая кавычки):

'2015-09-21 15:04:16.000' 

лучший способ включить это в код SAS, чтобы всегда сохраняйте свои даты и дату в своем представлении SAS и имеете отдельные переменные для ваших форматированных переменных SQL-сервера. Например.

Вычислить DateTime мы хотим работать с:

%let my_datetime = %sysfunc(datetime()); 

Создать две новые переменные с SQL сервером отформатированных штампов даты и времени. Я всегда называю моим &sql_start и &sql_end так, что они читают хорошо, и я никогда не должен думать об этом ...

%let sql_start = %sysfunc(sum(&my_datetime),mssqldt.); 
%let sql_end = %sysfunc(intnx(minute,&my_datetime,1),mssqldt.); 

Вы можете видеть, что для расчета sql_start я использовал функцию sum() в %sysfunc() и передается в DateTime SAS переменная. Я делаю это так, потому что он не меняет значение datetime и позволяет мне использовать второй параметр %sysfunc(), который применяет указанный формат к возвращаемому значению.

Для sql_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; 

Вот весь код в одном споре т (если вы уже определили формат):

%let my_datetime = %sysfunc(datetime()); 

%let sql_start = %sysfunc(sum(&my_datetime),mssqldt.); 
%let sql_end = %sysfunc(intnx(minute,&my_datetime,1),mysqldt.); 

%put &sql_start &sql_end; 

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' 
+0

Замечательный ответ Роберт - именно то, что я хотел. Спасибо, что нашли время, чтобы написать его подробно. – milcak

0

SAS сохраняет DateTimes как количество секунд, так, а не добавить одну минуту вы можете попробовать добавить & я минут * 60seconds/мин, чтобы получить правильный интервал.

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

EDIT: Это не будет работать, если у вас есть переменные символы, которые он появляется что вы делаете, но только если вы используете фактическое значение даты и время SAS.

+0

Благодарим вас за ответ Reeza, однако моя проблема заключалась в том, что я не могу добавить в & tmstmp_begin (с или без минут); Я думаю, это потому, что он хранится как строка в таблице sql. – milcak

+0

Обычно штамп даты и времени - это дата, но макро переменная будет символом, я немного изменил ответ, но ответ на вопрос Роберта, вероятно, еще предпочтительнее. Я думаю, что вышеупомянутое должно работать, хотя. – Reeza