#join #merge #sas #proc-sql
Вопрос:
Я пытаюсь объединить два набора данных на основе переменных office_id и office_id_flag, каждый из которых содержит 50 000 наблюдений.
переменные data1
- врп
- возраст
- латиноамериканец
- ID
- гонка
- Секс
- mental_ill
- mental_ill_dx
- идентификатор офиса
- office_id_flag
переменные data2
- er_vis
- adm_hr
- psych_hosp
- psych_vis
- регион
- region_rpc
- расходы
- идентификатор офиса
- 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 приводила к этим ошибкам:
- ПРЕДУПРЕЖДЕНИЕ: Переменная office_id уже существует в РАБОТЕ с файлами.как бы то ни было, имя_таблицы.
- ПРЕДУПРЕЖДЕНИЕ: Переменная 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 подходящим?