SAS: выполнить sql строк запроса из таблицы? - PullRequest
0 голосов
/ 10 февраля 2020

Если у меня есть таблица, содержащая sql строки запроса, подобные этой (столбец query)

id  query                                 n
——————————————————————————————-—————————————
1   select count(*) from tab where x=...
2   select count(*) from tab where x=...
... 

В SAS есть способ сохранить результаты этих запросов в другом столбце n ?

Ответы [ 3 ]

1 голос
/ 11 февраля 2020

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

Используемые функции взаимодействия:

  • dosubl, выполнить отдельный блок кода SAS во время выполнения STEP . Proc SQL запрос в этом случае.
    • Функция DOSUBL позволяет немедленное выполнение кода SAS ...
      DOSUBL выполняет код в другом исполнительном устройстве SAS ( известный как побочный сеанс )

  • into <em>:macro-variable</em>, сохранить результат в макропеременной
  • symget, получить результат из макросреды

Если вы запрашиваете одну и ту же собственную таблицу SAS снова и снова, вы можете включить:

  • sasfile, открывая набор данных в память, поэтому дисковый ввод-вывод происходит только один раз при повторном запросе к таблице

Пример

Запросы, как указано в вопросе, НЕ включают INTO пункт. Предполагая, что каждый запрос не имеет INTO И имеет один скалярный результат, предложение INTO может быть введено в строку запроса через TRANWRD.

data have;
  input;
  query = _infile_;
datalines;
select count(*) from sashelp.class where name between 'A' and 'F'
select count(*) from sashelp.class where name between 'F' and 'K'
select count(*) from sashelp.class where name between 'K' and 'O'
select count(*) from sashelp.class where name between 'O' and 'S'
select count(*) from sashelp.class where name between 'S' and 'ZZ'
select count(*) from sashelp.class where name between 'A' and 'K'
select count(*) from sashelp.class where name between 'A' and 'O'
select count(*) from sashelp.class where name between 'A' and 'S'
select count(*) from sashelp.class where name between 'A' and 'ZZ'
;

sasfile sashelp.class open;

data want;
  set have;

  * tweak 'presumed to be scalar' query;

  length into_query $1000; drop into_query;
  into_query = tranwrd (query, 'from', 'into :scalar_result from');

  rc = dosubl('proc sql noprint; ' || into_query);

  query_result = symget('scalar_result');
run;

sasfile sashelp.class close;

ods listing; proc print; run;

have pro c печать

                                                                                   query_
Obs                                  query                                   rc    result

 1     select count(*) from sashelp.class where name between 'A' and 'F'      0       4
 2     select count(*) from sashelp.class where name between 'F' and 'K'      0       8
 3     select count(*) from sashelp.class where name between 'K' and 'O'      0       2
 4     select count(*) from sashelp.class where name between 'O' and 'S'      0       3
 5     select count(*) from sashelp.class where name between 'S' and 'ZZ'     0       2
 6     select count(*) from sashelp.class where name between 'A' and 'K'      0      12
 7     select count(*) from sashelp.class where name between 'A' and 'O'      0      14
 8     select count(*) from sashelp.class where name between 'A' and 'S'      0      17
 9     select count(*) from sashelp.class where name between 'A' and 'ZZ'     0      19
1 голос
/ 11 февраля 2020

Просто для удовольствия - подход, использующий только pro c sql:

data queries;
input id :8. query :$100.;
infile datalines dsd;
datalines;
1,select count(*) as count from sashelp.class where sex = 'F'
2,select count(*) as count from sashelp.class where sex = 'M'
;
run;

proc sql noprint;
  select catx(' ','select ', id, ' as id,', substr(query, 7)) into :code
    separated by ' union all ' 
    from queries;
  create table want as
    &code;
quit;

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

1 голос
/ 11 февраля 2020

Вы можете сделать это, вызвав макрос в шаге данных, но в зависимости от того, как написан запрос, вам придется вызывать его в подзапросе в proc sql.

* 1003. *

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

data want;
set have;
run;

data _null_;
set have;
call execute(%nrstr(%run_query('||query||','||id||'))');
run;
...