Хроники лаборатории
Хитрые функции в SAS Base/Macro

Этот пост я пишу скорее даже для себя. С другой стороны, подобных материалов по SAS Base на русском исчезающе мало, так что может и пригодится кому-то ещё.

Сегодня решая забавную задачку по работе, понял, что мне не хватает произвольной, собственной функции. Как её можно создать в SAS? Ну для начала там есть макросы. Но это не то. Макросы в SAS - это скорее метапрограммирование: ты пишешь код, который потом при запуске сгенерирует обычный SAS Base-код и уже он пойдёт на исполнение. А мне нужно было (не вдаваясь в подробности) формировать из одной таблицы другую по шаблону третьей. Уверен, это можно было реализовать вкраплением SQL-запроса (SAS это тоже позволяет делать), но моя мысль заключалась несколько в другом: как бы так объявить обычную функцию, которая бы преобразовывала дающиеся на вход данные, да ещё с участием данных из других таблиц?

Язык SAS Base/Macro - весьма своеобразная датаориентированная среда, и то, что в языках типа Java или PHP решается на раз, в SAS требует принципиально другого подхода. Поэтому пришлось попотеть. Схематичный исходник и пояснения - под катом:
/* === Начальные данные === */

data users; /* Таблица с юзерами, отсюда потом будем брать имена */
infile datalines;
input id :8. name :$100.;
return;
datalines;
1 Anton
2 Boris
3 Catarina
4 Dmitry
5 Ermak
;
run;

data base(drop=i j); /* Таблица-шаблон. По ней потом будем создавать табличку с именами. Эту таблицу вообще случайными данными забиваем */
array id{6} 8;
do j=1 to 10 by 1;
do i=1 to 6 by 1;
id{i} = floor(6*rand("Uniform")); /* от 0 до 5, 0 - чтобы некоторые поля были пустые на выходе*/
end;
output;
end;
run;

/* === Основная магия тут === */

%macro macro_GetNameByID(); /* Макрос для чтения нужной строки из таблицы USERS */
data _null_;
set users(where=(id=&id));
call symputx('name',name);
%let name=&name;
run;
%mend get_Name_by_ID;

proc fcmp outlib=work.funcs.my;
/* Собственно, сама функция */
function get_name_by_id(id) $; /* $ как признак того, что функция возвращает именно строку, а не число */
length name $100;
rc=run_macro('macro_GetNameByID',id,name); /* Функция вызывает макрос. Макрос, приём! */
return(name);
endsub;
run;

options cmplib=work.funcs;

/* --- Конец магического блока --- */

/* === Основная работа: берём таблицу BASE, и в соотвествии с числами в ней создаём таблицу NAMES === */
data names(drop=i j id:);
set base;
array name{6} $ 100;
array id{6} 8;
do i=1 to 6 by 1;
name{i} = get_name_by_id(id{i});
end;
run;


Что получается? Примерно вот такое непотребство:

WORK.USERS

#idname
11Anton
22Boris
33Catarina
44Dmitry
55Ermak

WORK.BASE

#id1id2id3id4id5id6
1433004
2553010
3031104
4404014
5554530
6514404
7202101
8141033
9430522
10210414

WORK.NAMES

#name1name2name3name4name5name6
1DmitryCatarinaCatarina    Dmitry
2ErmakErmakCatarina  Anton  
3  CatarinaAntonAnton  Dmitry
4Dmitry  Dmitry  AntonDmitry
5ErmakErmakDmitryErmakCatarina  
6ErmakAntonDmitryDmitry  Dmitry
7Boris  BorisAnton  Anton
8AntonDmitryAnton  CatarinaCatarina
9DmitryCatarina  ErmakBorisBoris
10BorisAnton  DmitryAntonDmitry


RSS HTML рубрики: рабочееjuick twitter facebook вконтакте

Случайные записи впридачу:
Тангенциальное время (синематограф)
Поисковые запросы. (сайтоводство)
Вспоминая... (я в печати)

Откуда вы?   

Войти через loginza
Оставлять комментарии могут только
имеющие свой ЖЖ-, ЛИру-аккаунт или
еще какой openID (как так?).
Подписаться


Рубрики:

жизненное
аудио-я
видеомонтаж
фотоохота
ремонт
стихи
рассказы
синематограф
библиотека
фонотека
точка зрения
FAQ
приемчики
придумалось
ожидания-прогнозы
допридумано
рингтоны
это я так шучу
обои
микрозарисовки
опасный Интернет
я в печати
поездки-тусовки
смехоспам
мой код
футболки
игродром
подводная жизнь
сайтоводство
программы
персоны
LI.ru
аватарки
курсоры


Разное:

Полка с фильмами
Книжная полка
Полка с играми
Избранное


Календарь записей

2020 (7)
июнь (1)
май (1)
апрель (2)
март (2)
февраль (1)
2019 (3)
2018 (1)
2017 (10)
2016 (12)
2015 (3)
2014 (12)
2013 (10)
2012 (17)
2011 (84)
2010 (172)
2009 (228)
2008 (263)
2007 (154)
2006 (4)
2005 (1)
2004 (1)
2002 (1)
2001 (9)
2000 (9)
1999 (1)
© сайт разработан и поддерживается мной.