Я наткнулся на следующий фрагмент кода, в котором переменная top3
должна быть заполнена из таблицы have
, а не из массива чисел.
%let top3 = 14 15 42; /* This should be made obsolete.. */
%let no = 3;
proc sql;
create table want as
select *
from (select x, y from foo) a
%do i = 1 %to &no.;
%let current = %scan(&top3.,&i.); /* What do I need to put here? */
left join (select x, y from bar where z=¤t.) row_¤t.
on a.x = row_¤t..x
%end;
;
quit;
Таблица have
содержит x
s из строки и выглядит следующим образом:
i x
1 14
2 15
3 42
Теперь мне интересно, как мне изменить строку %let current = ...
, чтобы current
заполнялась из таблицы have
. Я знаю, как заполнить переменную макроса, используя proc sql
с select .. into
, но я боюсь, что то, как я сейчас поступаю, полностью противоречит философии SAS.
Когда данные поиска находятся в таблице, вы можете выполнить трехстороннее соединение без необходимости использования макроса SAS. Вы не предоставляете никаких данных, поэтому пример будет издеваться над некоторыми.
Пример:
Предположим, что основная запись имеет несколько связанных записей сведений, а записи сведений содержат значение z
, используемое для выбора в наборе результатов в соответствии с требуемой таблицей поиска z
.
data masters;
call streaminit(2020);
do id = 1 to 100;
do x = 1 to 100;
m_rownum + 1;
code = rand('integer', 10,45);
output;
end;
end;
run;
data details;
call streaminit(2020);
do date = 1 to 20;
do x = 1 to 100;
do rep = 1 to 5;
d_rownum + 1;
amount = rand('integer', 100,200);
z = rand('integer', 10,45);
output;
end;
end;
end;
run;
data zs;
input z @@; datalines;
14 15 42
;
proc sql;
create table want as
select
m_rownum
, d_rownum
, masters.id
, masters.x
, masters.code
, details.z
, details.date
, details.amount
from
masters
left join
details
on
details.x = masters.x
inner join
zs
on
zs.z = details.z
order by
masters.id, masters.x, details.z, details.date
;
quit;
Похоже, вы более или менее что-то транспонируете. Если это так, это довольно легко выполнимо в макросе/sql.
Во-первых, вот простая версия - без макроса.
proc sql;
create table class_t as
select * from (
select name from sashelp.class ) class
left join (
select name, age as age_Alfred
from sashelp.class
where name='Alfred') Alfred
on class.name = Alfred.name
;
quit;
Мы берем значение age из строки Alfred и помещаем его в основное соединение. Это не совсем то, что вы делаете, но похоже. (Я использую только одну таблицу, но вы, конечно, можете использовать две.)
Теперь, как мы можем расширить это, чтобы оно управлялось таблицей, а не писалось от руки? Макросы!
Во-первых, вот макрос — просто взять бит Альфреда и сделать его универсальным.
%macro joiner(name=);
left join (
select name, age as age_&name.
from sashelp.class
where name = "&name.") &name.
on class.name = &name..name
%mend joiner;
Во-вторых, мы смотрим на это и видим две вещи, которые нам нужно поместить в списки макросов: список переменных SELECT (мы будем получать одну новую переменную для каждого вызова) и список JOIN.
proc sql;
select cats('%joiner(name=',name,')')
into :joinlist separated by ' '
from sashelp.class;
select cats(name,'.age_',name)
into :selectlist separated by ','
from sashelp.class;
quit;
И тогда, мы просто называем это!
proc sql;
create table class_t as
select class.name,&selectlist. from (
select name from sashelp.class) class
&joinlist.
;
quit;
Теперь ваш набор данных, из которого вы вызываете списки макросов, возможно, представляет собой набор данных с тремя строками, которые у вас есть выше («есть»). Набор данных, из которого вы на самом деле получаете присоединяемые данные, — это какой-то другой набор данных («полоса»), верно? И затем те, к которым вы присоединяетесь, возможно, являются третьим набором данных («foo»). Здесь я просто использую один, для простоты, но концепция та же, просто разные источники.
Я не понимаю, как &selectlist.
может быть правильно заполнен вашим кодом. Я ожидаю, что будет (только в случае Alfred
) быть Alfred.age_Alfred
и полным соединением, которое возвращает ваш макрос %joiner()
. Я что-то упускаю из виду?
Почему в исходном запросе используется цикл %DO, а не просто
select x, y from bar where z in (&top3)
? У вас не может быть более одной переменной с именем Y, вы упростили свой пример?