Объединение списков и объединение групп в SAS Proc SQL - PullRequest
1 голос
/ 15 апреля 2019

У меня есть набор данных, который должен быть свернут на основе гранулярности (FIELD1 и FIELD2). Два поля метрик (METRIC1 и METRIC2) должны быть суммированы. До сих пор это кажется легкой задачей GROUP BY. Но у меня есть строковое поле (FLAG), которое тоже нужно свернуть, объединяя различные значения.

Входной набор данных:

enter image description here

Ожидаемый результат:

enter image description here

Эта операция может быть выполнена в Oracle с помощью функции LISTAGG (). Пожалуйста, помогите мне добиться того же в SAS Proc SQL.

Ответы [ 3 ]

2 голосов
/ 15 апреля 2019

Я не верю, что есть прямой способ сделать это в SAS.CATS (и аналогичные функции конкатенации) не являются функциями агрегирования.Было предложено добавить их несколько лет назад, но я ничего не узнал (см. эту ветку .)

Если я правильно понимаю, что вы делаетеявляется GROUP BY field1 / field2, SUM metric1 / metric2 и создает одно поле FLAG, которое объединяет все видимые значения полей FLAG (но не группирует по ним).

Способ, которым я бы обработал это, состоит в том, чтобы сначалавыполните агрегацию (field1 / field2), а затем соедините ее с отдельной таблицей, которая была просто field1 / field2 / flag.Вы могли бы сделать это проще всего на шаге данных, например:

data want;
  set have;
  by field1 field2;
  length flag_out $100; *or longer if you need longer;
  flag_out = catx(',',flag_out,flag);
  if last.field2 then output;
  rename flag_out=flag;
  drop flag;
run;

Это предполагает, что оно уже отсортировано по field1 / field2, в противном случае вам сначала нужно сделать это.

1 голос
/ 16 апреля 2019

Как уже говорилось, нет функции LISTAGG(), а также нет встроенной функции для создания пользовательской функции агрегирования. Тем не менее, есть две возможности, которые получают вывод.

Пример один

Шаг данных с обработкой DOW и хэшированием для отслеживания различных значений флага при конкатенации в группе.

data want;
  if 0 then set have; *prep pdv;
  length flags $200;

  declare hash _flags();
  _flags.defineKey('flag');
  _flags.defineDone();

  do until (last.f2);
    set have;
    by f1 f2;
    m1_sum = sum(m1_sum,m1);
    m2_sum = sum(m2_sum,m2);
    if _flags.find() ne 0 then do;
      _flags.add();
      flags = catx(',',flags,flag);
    end;
  end;

  drop m1 m2 flag;

  _flags.delete();
run;

Пример два

Создать пользовательскую функцию FCMP, используемую в SQL. Поскольку FCMP не может создать статистическую функцию, результат будет автоматически сопоставлен с исходными данными, которые затем должны быть отфильтрованы. Функция FCMP также использует хэш для отслеживания различных значений flag в группе.

proc fcmp outlib=sasuser.functionsx.package;

  function listagg(f1 $, f2 $, n, item $) $;
    length result $32000 index 8;

    static flag;
    static index;
    declare hash items();

    if flag = . then do;
      flag = 1;
      rc = items.defineKey('item');
      rc = items.defineDone();
    end;

    static items;

    index + 1;
    rc = items.replace();

    if index = n then do;
      declare hiter hi('items');
      result = '';
      do while (hi.next() = 0);
       result = catx(',',result,item);
      end;

      index = 0;
      rc = items.clear();

      return (result);
    end;
    else 
      return ("");

  endsub;
run;

options cmplib=sasuser.functionsx;

proc sql;
  create table wanted as 
  select * from 
  (
    select                      /* subselect is a remerge due to 'listagg' mimic */
      f1, 
      f2,
      listagg(f1, f2, count(*), flag) as flags,
      sum(m1) as m1,
      sum(m2) as m2
    from have
    group by f1, f2
  )
  where flags is not null                   /* filter the subselect */
;
quit;

В идеале хэш хэшей использовался бы, но FCMP обеспечивает создание экземпляра хеша только в операторе declare, и динамические хэши не могут быть созданы с помощью _new_. Пользователи SAS Viya смогут использовать новый компонентный объект Dictionary в функции FCMP и могут иметь словарь словарей для отслеживания различных значений флагов в каждой группе.

0 голосов
/ 17 апреля 2019

Спасибо всем за ваш ценный вклад. По-видимому, в SAS нет простого решения этого сценария. Учитывая более широкую картину требований, я решил заняться проблемой на уровне данных или добавить еще один промежуточный уровень представления. Я уверен, что многие указали на эту необходимость SAS, я поднял эту проблему и с SAS. Надеюсь, они изучат это и придумают функцию, аналогичную LISTAGG OR GROUP_CONCAT.

...