Обрезаем хвосты с пробелами в макропеременных через PROC SQL

Всем привет!

Пару лет назад была статья о работе с макропеременными, о том как сохранять значения без хвоста пробелов. Тогда речь шла о записи значений через DATA STEP.

В этой статье я поделюсь, как это можно сделать через PROC SQL.

Читать далее Обрезаем хвосты с пробелами в макропеременных через PROC SQL

Что нужно занать при создании макроперепенных?

Всем привет!
В сегодняшнем уроке поговорим о том как создавать макропеременные, а именно:
  • Чем отличается CALL SYMPUT от %LET ?
  • Как создавать в макросе глобальные макропеременные?
  • Что такое вложенность локальных макропеременных?
На все вышеперечисленные вопросы ответы вы найдете в приведенном ниже видео с примерами.
Хочу привести картинку к третьему вопросу со вложенностями локальных переменных:
Источник для данного урока вы можете посмотреть тут.
Если урок Вам понравился, пусть его увидит больше людей – сделайте репост в фейсбуке, вконтакте или google+ , а также жду Ваших комментариев.
С уважением,
Николай.

MSTORED SASMSTORE. Склад макрасов. Part1.

Всем привет.

Сегодня речь пойдет о макросах, а точнее о часто используемых макросах, а еще более точно о макросах, которые часто используются многими пользователями.

Довольно часто пользователи используют в своих программах маросы, написанные очень и очень давно.
Я бы даже сказал эти макросы для многих стали своего рода частью sas кода, т.е. своего рода стали как современный телефон — жить без него можно, но очень неудобно :).

А начну я с того, что происходит когда вы запускаете программу в которой присутсвтуе макрос. В этом случае компилятор начинает ы-же находиться скомпилированный макрос по следущему алгоритму:

1.  Сперва поиск происходит в текущей сесси пользователя, т.е. в папке Work.Sasmacr

Видно, что в указанном каталоге храниться макрос: Abc.

2.  Если название макроса не удалось найти в папке  Work.Sasmacr, то поиск происход в библиотеке определенной под SASMSTORE

B выглядит это так:

Как мы видим в данном каталоге имются макросы: Foobar, Secure, Secure1.

3.  Далее поиск осуществляется в библиотеке, определенной под SASAUTOS

4.  И конечный поиск идет по библиотке SASHELP из каталога Sasmacr из пункта 2.


Чаще всего папочка со скомпилированными макросами подцепляется в процессе создания сессии, чтобы уже при работе все макросы были доступны для использования.

P.S.  Более подромно материал можно посмотреть здесь.

Lock SAS Tables. Блокировка таблиц SAS. Part 2

Всем добрый день.

Начну сразу с рассмотрения TestCase.

Допустим у Вас есть процесс который обращается к SAS таблице, которая периодически обновляется (допустим неким ETL процессом).

Если в момент обновления таблицы вы попробуете к ней обратиться, то схватите ошибку «невозможности блокировки таблицы»:

Как можно обойти эту пролему?

Один из возможных вариантов — можно в цикле проверять залочена ли таблица и если да, через какой-то промежуток времени опять делать проверку и так до дех пор пока не истечет ожидаемое время либо до тех пор пока таблицу не отпустит сторонний процесс и вы тогда ее спокойно заблокируете.

Привожу макрос, проверяющий в цикле осободили ли таблицу и если да, то блокирует ее.

При этом рабочий лог может выглядеть следующим образом:

Из лога видно, что макрос висел почти 20 секунд и после этого таблица была отпущена и тутже заблокирована нашим процессом. После мы уже делаем то что хотим ( в данном случае просто переливаем данные).

Да, и не забывайте разблокировать талицу когда закончите с ней работать.

P.S. оригинал макроса можно посмотреть здесь.

Обработка ошибок через SAS Macro

Всем привет!
Я прошу прощения, что некоторое время не писал, так как проходил тренинг в Московском Тренинговом Центре. Если у Вас есть вопросы по поводу тренинга, то пишите: я всегда рад поделиться!
В данной статье я опишу достаточно простой способ обработки ошибок в SAS.

Недавно я столкнулся с задачей, где требовалось обрабатывать ошибку связанную с неправильной работой БД Oracle. То есть, например, необходимо было записать что-то, а база недоступна.
Начну по порядку. Ошибки записываются в стандартные автоматические макропеременные:
&SYSERR
&SYSERRORTEXT
&SYSWARNINGTEXT
Для того, чтобы код отработал после ошибки (которая по идее прекращает работу программы) необходимо создать макрос и поместить его в конец программы.
На официальном сайте очень подробно расписано какие значения может принимать макропеременная SYSERR. Данная переменная содержит коды по ТИПАМ ошибок. И используя, например, следующий код можно проверить условие на то, что есть ошибка или нет:
%MACRO ERROR_CHECK1();
     %IF &SYSERR NE 0 %THEN
            %DO;
                %PUT %SYSERR;
                * <В ДАННОЕ МЕСТО МОЖНО ВСТАВИТЬ НЕОБХОДИМЫЙ КОД!> ;
            %END:
%MEND;
%ERROR_CHECK1;
К сожалению, не всегда и не во всех приложениях SAS можно использовать данную переменную. Особенно это заметно, когда «проваливаешься» на стороннюю БД.
В этом случае приходят на помощь SYSERRORTEXT и SYSWARNINGTEXT. На официальном сайте есть несколько примеров по работе с ними. Данные переменные содержат тексты ошибок и предупреждений, даже если &SYSERR = 0. В качестве примера можно использовать следующий код, которые обрабатывает оракловые ошибки:
%MACRO ERROR_CHECK2();
     %IF  %SYSFUNC(FIND(&SYSERRORTEXT, ‘ORACLE EXECUTE ERROR’,1)) %THEN
            %DO;
                %PUT %SYSERRORTEXT;
                * <В ДАННОЕ МЕСТО МОЖНО ВСТАВИТЬ НЕОБХОДИМЫЙ КОД!> ;
            %END:
%MEND;
%ERROR_CHECK2;
Также есть интересные примеры на сайте support.sas.com, связанные с обработкой ошибок. google.com в данном случае поможет =)
В некоторых приложениях SAS существуют дополнительные макропеременные. Например, в SAS Customer Intelligence Studio можно выделить две: MAError и MAMsg. Принцип работы примерно такой-же, как и для стандартных ошибок, описанных выше.
На этом всё!
До скорых встреч!

TRANWRD, TRANSTRN функции и макропеременные

Всем привет!

Не так давно я столкнулся с необходимостью замены некоторых символов в макропеременных. Например, задача записать в название файла текущее время в формате HHMM.


Как вы наверное знаете, это можно сделать несколькими способами.

Я решил сделать так:
%let time = %sysfunc(TIME(),hhmm.);

В этом случае мы получим результат в виде hh:mm. Всё было бы отлично, если бы не одно но: система MS Windows не приемлет в названии файлов символы типа » : «.

Попробуем заменить двоеточие на значок нижнего подчёркивания » _ «.
Воспользуемся функцией TRANWRD (можно и TRANSTRN), синтаксис которой следующий:
TRANWRD(источник, что меняем, на что меняем)
Описание функции можно найти на официальном сайте.

Вставляем эту функцию в макрокод, как если бы вставляли в обычный код:
%let time = %sysfunc(tranwrd(%sysfunc(TIME(),hhmm.), «:» , «_»));
Но он не сработал, и результат остался тем же в формате hh:mm.

Так в чём же дело?
А дело в следующем:

  • В макрокоде нет необходимости использовать кавычки, а если они стоят, то они будут считаться частью текста. То есть, «:» — это 3 символа, которых нету в значении времени, а значит и нечего заменить.
  • Если есть необходимость заменить пробел, то в этом случае приходит на помощь %STR(letter), где на месте letter будет стоять пробел или любой другой символ, который необходимо заменить.

То есть, теперь код может выглядеть следующим образом:

%let time = %sysfunc(transtrn(%sysfunc(TIME(),hhmm.),: ,_));

или

%let time = %sysfunc(transtrn(%sysfunc(TIME(),hhmm.),%str(:) ,%str(_)));

На этом всё!
Спасибо за прочтение и до скорых встреч!

Передача макропеременных на сторону Oracle

Всем привет!

Данная статья достаточна проста, но она позволяет предостеречь читателей от потерянного времени на поиск ошибки, которая может быть не очевидна.


Допустим была создана макропеременная:
%let id = 1;

Сразу напомню, что макропеременная &id имеет тип char.

Далее мы хотим передать эту переменную в БД Oracle через pass through. В отличии от работы в SAS, кавычки не требуются.
proc sql noprint;
    connect to oracle as myora (user=»example» password=»example» path=example);
         execute (create table example (id number)) by myora;
         execute (insert into example values (&id)) by myora;
    disconnect from myora;
quit;

Как мы можем убедиться, происходит неявное преобразование и в табличку записывается числовое значение.

Но допустим, вам надо поместить это значение в какую-то процедуру?
Например, example.test(id as number).
proc sql noprint;
    connect to oracle as myora (user=»example» password=»example» path=example);
        execute (
            begin
                example.test(&d);
            end;       
            ) by myora;
    disconnect from myora;
quit;

И вроде бы всё нормально, но не происходит вызов процедуры, и не происходит ошибка Oracle.

Проблема опять же, на поверхности. В данном случае, требуется явно преобразовать тип данных, чтобы Oracle считал как необходимый нам тип. Делаем это функцией to_number.

proc sql noprint;
    connect to oracle as myora (user=»example» password=»example» path=example);
        execute (
            begin
                example.test(to_number(&sess_id));
            end;       
            ) by myora;
    disconnect from myora;
quit;

Всё! Спасибо за прочтение!
До скорых встреч!

Создание макропеременных через CALL SYMPUT

Всем привет!

Данная статья — это голая калька с другой статьи.

К сожалению, на habrahabr.ru нету как такого раздела или публикаций на тему SAS. И искать там что-либо оказывается затруднительным, если не знаешь, что искать =)
Данный же ресурс целиком и полностью предназначен для SAS пользователей.


Краткая предыстория проблемы, решение которой пришлось сначала искать самому.
Задача считать название файлов из директории и записать их в другую директорию.

filename read1 ftp » ls lsfile=’*.txt’ cd=»» &ftp;
data read1;
    length name $ 60;
    infile read1;
    input name $;
run;

Тут возникает вопрос, как записать значение данной переменной в макропеременную так, чтобы обрезать хвост. Не стану вдаваться в подробности какие способы были использованы для решения данной проблемы, а вставлю текст, который сразу всё расставит на свои места.

Источник http://habrahabr.ru/post/142147/
За что автору большой плюс в его карму! =)

===============================================================
Добрый день, дорогие читатели.
В этой статье я расскажу о двух процедурах языка SAS Base и о небольших тонкостях их применения.

Тем, кто уже достаточно работает с этим языком, эти вещи покажутся элементарными, но для начинающих они, возможно, позволят избежать грабли, на которые я наступил в самом начале моего знакомства с SAS Base.

CALL SYMPUT

Call Symput используется для случаев, когда значение переменной в шаге данных (datastep) нужно присвоить макропеременной.
Синтаксис: call symput ("<макропеременная>", <символьное значение>)

Первый аргумент в процедуре symput — это название макропеременной, которой необходимо присвоить значение второго аргумента.

Второй аргумент — это символьное значение, которое будет присвоено макропеременной. Второй аргумент всегда должен быть именно символьным, в противном случае, численное значение должно быть конвертировано в символьную переменную, прежде чем присваивать его макропеременной. Если Вы не станете приводить тип, это может обернуться проблемами. В таком случае SAS автоматически конвертирует численное значение переменной в символьное значение, прежде чем присвоит его макропеременной, и выведет в лог сообщение о том, что было произведено конвертирование.

Пример:
data _null_;
count=1978;
call symput('count',count);
run;
%put &count;

19 data _null_;
20 count=1978;
21 call symput('count',count);
22 run;

NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column).
21:21
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds

23 %put &count;
1978

Хоть значение макропеременной count и было определено как 1978, SAS выдал замечание, гласящее
NOTE: Numeric values have been converted to character values at the places given by: (Line):(Column).
21:21

Чтобы избежать этого, Вам всё же стоит осуществить конвертирование численного значения в символьное, прежде чем присваивать его макропеременной. Вот, например, как это можно сделать:

data _null_;
count=1978;
call symput('count',strip(put(count,8.)));
run;
%put &count;

29 data _null_;
30 count=1978;
31 call symput('count',left(put(count,8.)));
32 run;

NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds

33 %put &count;
1978

Примечания:

  1. Несмотря на то, что мы создали переменную при помощи CALL SYMPUT, эта макропеременная не может быть использована напрямую в том же datastep’е. Причина такого явления — макро код компилируется и выполняется до того, как будет скомпилирован и выполнен datastep. Так что, макропеременная, создающаяся CALL SYMPUT, не будет доступна в datastep в силу того, что эта макропеременная будет создана и присвоена только после или во время выполнения кода datastep.
    (В случае, если Вам всё же понадобится доступ к той же макропеременной внутри datastep, Вы, разумеется, сумеете это сделать, при помощи двух разных макрофункций — RESOLVE или SYMGET)
  2. SAS всегда выравнивает численные значения по правому краю, что приводит к пробелам в начале символьной переменной при конвертации, если значение численной переменной было меньше её длины. Чтобы избавиться от этих пробелов, используйте функции, удаляющие все ведущие пробелы (как в примере выше).
  3. Если процедура CALL SYMPUT используется вне макроса (т.е. в открытом коде), она создаёт глобальную макропеременную, тогда как при использовании внутри макроса она создаст локальную.

CALL SYMPUTX

Процедура CALL SYMPUTX была анонсирована SAS в 9 версии с целью обойти ловушки CALL SYMPUT.
Преимущества CALL SYMPUTX перед CALL SYMPUT включают в себя:

  1. SYMPUTX автоматически конвертируют численные переменные в символьные перед присваиванием их макропеременной. (Вы больше не нуждаетесь в ручной конвертации при помощи выраждения PUT как в вышеприведённом примере)
  2. CALL SYMPUTX удаляет ведущие и хвостовые пробелы. Так что необходимость функций, наподобие STRIP или LEFT, для очистки от лишних пробелов, отпадает.

Синтаксис: call symputx ("<макропеременная>", <символьное значение>, <таблица символов>)

Первые два аргумента аналогичны аргументам CALL SYMPUT. Третий аргумент (таблица символов) опционален и может принимать значения G, L или F. Если Вы укажете G, макропеременная будет создана в глобальной таблице символов, если же Вы укажете L, SAS сохранит макропеременную в локальной таблице. Если третий аргумент не указывать или установить его как F, CALL SYMPUTX будет вести себя аналогично CALL SYMPUT.

Пример:
data _null_;
count=1978;
call symputx('count',count,’G’);
run;
%put &count;

29 data _null_;
30 count=1978;
31 call symputx('count',count,'G');
32 run;

NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds

33 %put &count;
1978

Примечание: Если бы Вы использовали CALL SYMPUT вместо CALL SYMPUTX, программа выполнилась бы идентично, но в лог было бы выдано замечание об автоматической конвертации численного значения в символьное.

Простой способ запомнить разницу между CALL SYMPUT и CALL SYMPUTX:
(взято со страницы Using_the_SAS_V9_CALL_SYMPUTX_Routine на SAScommunity.org)

Процедура SAS V9 CALL SYMPUTX позволяет Вам сэкономить нажатия клавиш и создать более компактный и понятный код.
Вместо использования
call symput('macrovar', trim(left(charvar)));
для создания макропеременной с символьной строкой, которая может содержать лишние пробелы, Вам стоит применить SYMPUTX:
call symputx('macrovar', charvar);

SAS Base. Check create table. Проверка наличия таблицы.

Всем добрый день!

Сегодня речь пойдет о проверке наличия таблицы в библиотеке.

Бывают такие ситуации, когда табличка по тем или иным причинам не создалась, но используется дальше в Вашем коде.
В таких случаях мы получаем сообщение об ошибке, что данной таблице не существует. Наш код прерывается и процесс не отрабатывает.

Как этого можно избежать?

Я Вам предлагаю следующий способ проверки с помощью проверочного макроса, где вначале вы проверяете наличие таблицы, а затем если все хорошо запускаете оставшуюся часть кода.

Макрос выглядит следующим образом:

При этом основная идея заключается в проверке нахождения нашей таблицы в dictionary.tables.

Лог выполнения данного макроса выглядит следующим образом в зависимости есть таблица или нет:

Ниже привожу видео версию данного урока:

До скорых встреч.

С уважением,
Николай.

SAS Macro variable and ampersands.

Всем привет!

В сегодняшнем уроке рассмотрим такой интересный момент, как процесс компиляции макро переменных в зависимости от количества амперсандов стоящих перед этой переменной.

Для лучшего понимания компиляции советую подключить опцию: options symbolgen;

И так давайте рассмотрим пример:
Создадим две макро  переменных, причем значение первой макро переменной является названием второй.

В данном примере все понятно. Теперь добавим еще один амперсанд:

Вот теперь становиться интересней. В данном случае мы видим, что двойной амперсанд превратился в одинарный и результат получился как в первом случае.

Добавим еще один амперсанд:

Теперь мы видим, что на первом шаге два амперсанда были превращены в один, а следующий (т.к. он остался один) был расценен как макро переменная и вернул значение firstmacro. На следующем шаге наш амперсанд (который получился из двух первых) был применен уже к firstmacro и мы получили в результате значение second_.
Рассмотрим четыре амперсанда:
Здесь все просто. Две пары схлопнулись в два аперсанды и они уже затем опять схлопнулись в один. 
Рассмотрим пять аперсандов:
В принципе здесь также по аналогии все понятно:
&&&&&macro1 =  (&&)(&&)(&macro1) -> &&firsmacro=(&&)firstmacro -> &firstmacro -> _second.
Далее привожу видео, где эксперимент проводился с 6 и 7 амперсандами.

Источник к данной статье можно посмотреть здесь!
С уважением,
Николай.