Как объединить две базы данных с помощью proc sql с использованием двух переменных

#join #merge #sas #proc-sql

Вопрос:

Я пытаюсь объединить два набора данных на основе переменных office_id и office_id_flag, каждый из которых содержит 50 000 наблюдений.

переменные data1

  1. врп
  2. возраст
  3. латиноамериканец
  4. ID
  5. гонка
  6. Секс
  7. mental_ill
  8. mental_ill_dx
  9. идентификатор офиса
  10. office_id_flag

переменные data2

  1. er_vis
  2. adm_hr
  3. psych_hosp
  4. psych_vis
  5. регион
  6. region_rpc
  7. расходы
  8. идентификатор офиса
  9. office_id_flag

Я впервые попробовал это в процедуре слияния шагов с данными, потому что я знаю, как это работает, и в результате набор данных содержал 50 000 наблюдений и 17 переменных, что для меня имеет смысл. Код слияния:

 proc sort data=data1; by office_id; run;
proc sort data=data2; by office_id; run;

data work.merge_datastep;
    merge data1 (in=dem) data2 (in=hosp);
    by office_id;
    if dem and hosp;
run;
*53000 observations and 17 variables;
 

Я перепробовал так много типов слияния SQL, и каждый из них создает набор данных с 56000 наблюдениями и 17 переменными, что не имеет смысла.

Вот что я попробовал в SQL:

 proc sql;
create table sql_outerjoin as 
 select * 
 from data1 full outer join data2 on data1.office_id=data2.office_id;
quit;


proc sql;
create table sql_leftjoin as 
 select * from data1 left outer join data2 on data1.office_id=data2.office_id;
quit;

proc sql;
create table work.sql_innerjoin as
select data1.*, data2.*
from work.data1, work.data2
where data1.office_id=data2.office_id;
quit; 

proc sql ;
create table sql_try1 as 
select one.*, two.*
from data1 as one
left join data2 as two
on (one.office_id = two.office_id and one.office_id_flag= two.office_id_flag);
quit;


proc sql;
create table sql_try3 as
select coalesce(a.office_id, b.office_id) as ID
from data1 a
full join data2 b
on a.ID = b.ID;
quit;

proc sql;
  create table sparcs_1 as
  select * 
  from data1, data2
  where data1.office_id=data2.office_id;
quit;


proc sql;
create table work.sql_leftjoin2 as
select s.*, d.*
from work.data1 as s left join work.data2 as d
on s.office_id=d.office_id;
quit; 
 

Кроме того, каждая из этих попыток proc sql приводила к этим ошибкам:

  1. ПРЕДУПРЕЖДЕНИЕ: Переменная office_id уже существует в РАБОТЕ с файлами.как бы то ни было, имя_таблицы.
  2. ПРЕДУПРЕЖДЕНИЕ: Переменная office_id_flag уже существует в РАБОТЕ с файлами.как бы то ни было, имя_таблицы.

Я бы хотел, чтобы конечный результат был идентичен процедуре слияния datastep и чтобы все переменные и 50 000 наблюдений совпадали по office_id и office_id_flag.

Я не в своей тарелке и, очевидно, стреляю в темноте с этим. У кого-нибудь есть какие-нибудь предложения?

Комментарии:

1. Почему у вас есть несколько наблюдений для одного и того же значения OFFICE_ID? Каковы переменные, которые уникально идентифицируют наблюдения в каждом из входных наборов данных? Насколько он стал больше? Возможно ли, что дубликаты предназначены только для одного значения OFFICE_ID? Возможно, отсутствует vlaue или код, означающий неизвестный идентификатор?

Ответ №1:

Если количество наблюдений не увеличивается на этапе слияния данных, но увеличивается в соединениях SQL, то у вас есть данные, которые не являются уникальными для ключа слияния/объединения. SAS не увеличит количество строк в слиянии при наличии повторяющихся строк — это также, вероятно, не будет делать то, что вы хотите, но может сделать что-то приемлемое. SQL, однако, создаст (в зависимости от того, как вы это сделаете) дополнительные строки для каждой комбинации.

Как это решить? Убедитесь, что у вас есть уникальный ключ соединения, при котором ни одна пара (или более) строк не имеет одного и того же значения в обоих наборах данных. Или подумайте о правильном типе соединения для имеющихся у вас данных — это может потребовать обобщения данных.

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

 proc sql;
  create table sparcs_1 as
  select * 
  from data1, data2
  where data1.office_id=data2.office_id
    and data1.office_id_flag=data2.office_id_flag
  ;
quit;
 

или

 proc sql;
  create table sparcs_1 as
  select * 
  from data1 inner join data2
  on data1.office_id=data2.office_id
    and data1.office_id_flag=data2.office_id_flag
  ;
quit;
 

Оба они требуют, чтобы строка совпадала с обеими переменными и исходила из обеих таблиц. Но это не то , что делает ваше слияние шагов с данными SAS — это зависит только от office_id того, так что это может дать другой результат. Скорее всего, вы не сможете идеально воспроизвести это объединение в SQL — без добавления какой — либо нумерации строк-потому что способ, которым SAS выполняет слияние, просто отличается, и обычно это не то, что вы действительно хотели бы сделать в SQL.

Во-вторых, ваши предупреждения связаны с тем, что вы делаете такие вещи, как это:

 select a.*, b.* 
 

Если одна и та же переменная присутствует в обоих наборах данных, то вы запрашиваете ее дважды. Отсюда и предупреждение. На самом деле это не проблема, если ключ соединения является единственной переменной, которая перекрывается — тогда результат будет тем, что вы хотите, просто с предупреждением, — но вы можете удалить его, явно перечислив нужные переменные по крайней мере из одной из таблиц. Лучше всего вообще не использовать * , но это понятно, особенно когда в одной таблице много переменных.

Комментарии:

1. Спасибо, Джо! Это объясняет предупреждение и дополнительные наблюдения. Теперь я попробовал этот код: proc sql ; create table sql_try4 as select data1.*, data2.er_vis, data2.adm_hr, data2.psych_hosp, data2.psych_vis, data2.region, data2.region_rpc, data2.charges from data1 left join data2 on (data1.pme_id = data2.pme_id and data1.pme_id_flag= data2.pme_id_flag); quit; и все еще вижу дополнительные наблюдения. Как бы я суммировал эти данные?

Ответ №2:

Спасибо, Джо! Ваши комментарии были очень полезны.

В итоге я добавил номер строки на основе строки наблюдения (из этого ранее заданного вопроса https://communities.sas.com/t5/SAS-Procedures/PROC-SQL-QUESTION-How-to-add-a-row-number-to-a-table-observation/td-p/167770), и тестирование полученного набора данных как в SAS, так и в proc sql.

Код здесь:

 proc sql;
  create table rows1 as
    select monotonic() as row, *
      from work.data1;
quit;

proc sql; 
    create table rows2 as 
        select monotonic() as row, *
            from work.data2;
quit;

proc sql ;
create table sql_rowmerge1 as 
select rows1.*, row2.er_vis, row2.adm_hr, row2.psych_hosp, row2.psych_vis, row2.region, row2.region_rpc, row2.charges
from rows1
left join rows2
on (rows1.row = rows2.row and rows1.office_id = rows2.office_id and rows1.office_id_flag= rows2.office_id_flag);
quit;
 

Как вы и предлагали, объединение на основе 3 условных переменных, а не только 2 (вероятно, не уникальных) переменных, было тем, что соответствующим образом объединило оба набора данных. Полученный набор данных теперь содержит правильные 50 000 наблюдений.

Еще раз спасибо — Это было здорово! Я узнал новый метод!

Комментарии:

1. Так зачем вообще использовать код PROC SQL, если вы просто собираетесь перепрыгнуть через все эти обручи, чтобы заставить его работать как код шага данных? Просто выполните шаг с данными. Гораздо проще, быстрее, понятнее.

2. Я согласен — я бы предпочел использовать шаг данных и закончил его в меньшем количестве строк, но использование proc sql является частью задания.

3. «задание»? От кого? Спросите их, почему они хотят, чтобы вы использовали неподходящий инструмент? Или, возможно, в данных, которые вы не понимаете, есть что-то такое, что делает использование кода SQL подходящим?