Разработка нового номера РК для уникальной записи - PullRequest
0 голосов
/ 21 апреля 2020

Я разработчик SAS. Я начинаю проект, который требует, чтобы я присвоил номер RK уникальной записи. Каждое извлечение получит данные, которые уже существуют в целевой таблице, а некоторые - нет. Например.

Исходные данные:

Name
A
B
C
D
E

Целевая таблица:

Name RK
A    1
B    2
C    3

Когда я загружаю, я хочу вставить D и E в целевую таблицу с помощью РК 4 и 5 соответственно. В настоящее время я могу подумать о поиске ha sh из источника с целевой таблицей. Для данных, которые не отображаются с использованием объекта ha sh, поле RK будет пустым. Я добавлю максимальное количество RK из целевой таблицы и добавлю к нему 1, добавив в нее D & E.

Я не уверен, является ли это наиболее эффективным способом сделать это. Есть ли еще более эффективный способ?

1 Ответ

0 голосов
/ 21 апреля 2020

Вы могли бы использовать га sh, чтобы определить, существует ли какое-либо имя (я назову его значение ) в целевой таблице. Однако необходимо будет отслеживать новые ключи, выводить их в конце шага, а затем PRO C APPPEND'd к целевой таблице (я назову ее master ).

В случае простого обновления мастер-таблицы новыми значениями RK, традиционный подход SAS заключается в использовании шага DATA для ИЗМЕНЕНИЯ уникальной ключевой таблицы с ключом. Шаблон кодирования:

  SET <source>
  MODIFY <master> KEY=<value> / UNIQUE;
  ... _IORC_ logic ...

Пример:

% * Создание исходных данных и основной таблицы;

data have1 have2 have3 have4 have5;
  call streaminit(123);

  value = 2020; output; output; output;

  do _n_ = 1 to 2500;
    value = ceil(rand('uniform', 5000));
    select;
      when (rand('uniform') < 0.20) output have1;
      when (rand('uniform') < 0.20) output have2;
      when (rand('uniform') < 0.20) output have3;
      when (rand('uniform') < 0.20) output have4;
      otherwise output have5;
    end;
  end;
run;

data have6;
  do _n_ = 1 to 20;
    value = 2020;
    output;
  end;
run;

* Create the unique keyed master table;
* Typically done once and stored in a permanent library.;

proc sql;
  create table keys (value integer, RK integer);
  create distinct index value on work.keys;
quit;

% * Макрос для добавления новых значений RK по мере необходимости;

%macro RK_ASSIGN(master, data);
  %local last;
  proc sql noprint;
    select max(RK) into :last trimmed from &master;
  quit;

  data &master;
    retain newkey %sysevalf(0&last+0);  %* trickery for 1st use case when max(RK) is .;
    set &data;
    modify &master key=value / unique;
    if _iorc_ eq %sysrc(_DSENOM);
    newkey + 1;
    RK = newkey;
    output;
    _error_ = 0;
  run;
%mend;

%* Use the macro to process source data;

%RK_ASSIGN(keys,have1)
%RK_ASSIGN(keys,have2)
%RK_ASSIGN(keys,have3)
%RK_ASSIGN(keys,have4)
%RK_ASSIGN(keys,have5)
%RK_ASSIGN(keys,have6)

enter image description here

Вы можете увидеть принудительные повторы значения 2020 в исходных данных только RK'd один раз в основной таблице, и нет ошибок во время обработки.

Если вы хотите backfill , исходные данные с найденным или назначенным значением RK будут дополнительными шаги. Вы можете обновить пользовательский формат или сделать традиционное левое соединение. Если вы хотите сосредоточиться на обратной засыпке во время чтения исходных данных, HA SH step + APPEND новый шаг RK может быть предпочтительным.

Пример 2 Основная таблица названа values

HA SH версия с назначением RK, добавленным к исходным данным. Новые выходные и добавленные значения РК.

proc sql;
  create table values (value integer, RK integer);
  create distinct index value on work.values;


%macro RK_HASH_ASSIGN(master,data);
  %local last;
  proc sql noprint;
    select max(RK) into :last trimmed from &master;
  quit;

  data &data(drop=next_RK);
    set &data end=end;

    if _n_ = 1 then do;
      declare hash lookup (dataset:"&master");
      lookup.defineKey("value");
      lookup.defineData("value", "RK");
      lookup.defineDone();

      declare hash newlookup (dataset:"&master(obs=0)");
      newlookup.defineKey("value");
      newlookup.defineData("value", "RK");
      newlookup.defineDone();
    end;

    retain next_RK %sysevalf(0&last+0);  %* trick;

    * either load existing RK from hash, or compute and apply next RK value;
    if lookup.find() ne 0 then do;
      next_RK + 1;
      RK = next_RK;
      lookup.add();
      newlookup.add();
    end;

    if end then do;
      newlookup.output(dataset:'work.newmasters');
    end;
  run;

  proc append base=&master data=work.newmasters;
  proc delete data=work.newmasters;
  run;
%mend;

%RK_HASH_ASSIGN(values,have1)
%RK_HASH_ASSIGN(values,have2)
%RK_HASH_ASSIGN(values,have3)
%RK_HASH_ASSIGN(values,have4)
%RK_HASH_ASSIGN(values,have5)
%RK_HASH_ASSIGN(values,have6)

% * Сравните две стратегии назначения, без различий!;

proc sort force data=values(index=(value));
  by RK;
run;

proc compare noprint base=keys compare=values out=diffs outnoequal;
by RK;
run;
----- LOG -----
2525  proc compare noprint base=keys compare=values out=diffs 

outnoequal  <------------- do not output when data is identical ;

;
2526  by RK;
2527  run;

NOTE: There were 215971 observations read from the data set WORK.KEYS.
NOTE: There were 215971 observations read from the data set WORK.VALUES.
NOTE: The data set WORK.DIFFS has 0 observations and 4 variables.   <--- all the same ---
NOTE: PROCEDURE COMPARE used (Total process time):
      real time           0.25 seconds
      cpu time            0.26 seconds


...