使用 %if %then %else 的 Sas 宏条件连接
Sas macro conditional join using %if %then %else
我正在尝试连接两个 table,权重 1 和权重 2。
我想先在 ID1=ID2 上加入这两个 table。
如果缺少 ID,我将加入 DOB1=DOB2。
我希望程序比较 table 中的每一行。
但是sas看到weight2缺少第一个IDtable,就完全切换到else语句,用DOB1=DOB2加入
我的理想结果是连接四行。但现在 sas 只给了我三行。
data weight1;
input ID1 $ Week1 DOB1;
datalines;
1111 195 101
2222 220 102
3333 173 103
4444 135 104
;
proc print data=weight1;
run;
data weight2;
infile datalines missover;
input ID2 $ Week2 DOB2;
datalines;
195 101
2222 220 102
3333 173 103
4444 135 104
;
proc print data=weight2;
run;
options mlogic symbolgen mprint;
%macro test ;
proc sql;
create table final as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
%if %sysfunc(exist(b.ID2)) %then
inner join weight2 b
on a.ID1 = b.ID2;
%else
/*%if %sysfunc(not exist(b.IDnumber))*/
inner join weight2 b
on a.DOB1 = b.DOB2
;
;
quit;
%mend test;
%test
SAS 日志:
LOGIC(TEST): Beginning execution.
MPRINT(TEST): proc sql;
MLOGIC(TEST): %IF condition %sysfunc(exist(b.ID2)) is FALSE
MPRINT(TEST): create table final as select a.ID1, a.DOB1, b.ID2,b.DOB2 from weight1 a inner join weight2 b on a.DOB1 = b.DOB2 ;
NOTE: Table WORK.FINAL created, with 3 rows and 4 columns.
这是我理想中的结果
ID1 DOB1 ID2 DOB2
1111 101 101
2222 102 2222 102
3333 103 3333 103
4444 104 4444 104
如果您像信任 ID 一样信任 DOB 上的连接,则可以简单地执行 on a.ID1 = b.ID2 or a.DOB1 = b.DOB2
。但我认为当 ID 不丢失时,DOB 匹配可能会给出一些错误的结果。
您可以先 select 具有两组 ID 的所有行,然后 select DOB 匹配但缺少任一 ID 的所有行。使用 union
将它们放入相同的 table。我现在无法测试我的代码,但是是这样的:
proc sql;
create table final as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1(where=(not missing(ID1)) a
inner join weight2(where=(not missing(ID2)) b
on a.ID1 = b.ID2
union
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
inner join weight2 b
on a.DOB1 = b.DOB2 and (missing(ID1) or missing(ID2))
;
case
表达式可用作连接条件。
不要使用宏。您对 %sysfunc(exist
的使用是错误的, exist
函数检查是否存在数据集,并且 %sysfunc
在源代码编译之前执行,而不是在 SQL 执行时间。
使用 case 表达式计算相等性检查的先决条件。
示例:
data weight1;
input ID1 $ Week1 DOB1;
datalines;
1111 195 101
2222 220 102
3333 173 103
4444 135 104
;
data weight2;
infile datalines missover;
input ID2 $ Week2 DOB2;
datalines;
. 195 101
2222 220 102
3333 173 103
4444 135 104
;
proc sql;
create table want as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
join weight2 b
on case
when (a.id1 is not missing and b.id2 is not missing) then a.id1=b.id2
when (a.dob1 is not missing and b.dob2 is not missing) then a.dob1=b.dob2
else 0
end
;
注意:在真实数据的情况下,每行 table 中有不止一行缺少 id 且出生日期相同,这将导致结果中出现乘法行数效应 table .比如这个样本数据:
1111 195 101
2222 220 102
3333 173 103
4444 135 104
. 145 105 ***
. 175 105 ***
和
. 195 101
2222 220 102
3333 173 103
4444 135 104
. 155 105 ***
. 166 105 ***
4 = 2 x 2 个来自加星标数据的结果行。
我正在尝试连接两个 table,权重 1 和权重 2。 我想先在 ID1=ID2 上加入这两个 table。 如果缺少 ID,我将加入 DOB1=DOB2。 我希望程序比较 table 中的每一行。 但是sas看到weight2缺少第一个IDtable,就完全切换到else语句,用DOB1=DOB2加入
我的理想结果是连接四行。但现在 sas 只给了我三行。
data weight1;
input ID1 $ Week1 DOB1;
datalines;
1111 195 101
2222 220 102
3333 173 103
4444 135 104
;
proc print data=weight1;
run;
data weight2;
infile datalines missover;
input ID2 $ Week2 DOB2;
datalines;
195 101
2222 220 102
3333 173 103
4444 135 104
;
proc print data=weight2;
run;
options mlogic symbolgen mprint;
%macro test ;
proc sql;
create table final as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
%if %sysfunc(exist(b.ID2)) %then
inner join weight2 b
on a.ID1 = b.ID2;
%else
/*%if %sysfunc(not exist(b.IDnumber))*/
inner join weight2 b
on a.DOB1 = b.DOB2
;
;
quit;
%mend test;
%test
SAS 日志:
LOGIC(TEST): Beginning execution.
MPRINT(TEST): proc sql;
MLOGIC(TEST): %IF condition %sysfunc(exist(b.ID2)) is FALSE
MPRINT(TEST): create table final as select a.ID1, a.DOB1, b.ID2,b.DOB2 from weight1 a inner join weight2 b on a.DOB1 = b.DOB2 ;
NOTE: Table WORK.FINAL created, with 3 rows and 4 columns.
这是我理想中的结果
ID1 DOB1 ID2 DOB2
1111 101 101
2222 102 2222 102
3333 103 3333 103
4444 104 4444 104
如果您像信任 ID 一样信任 DOB 上的连接,则可以简单地执行 on a.ID1 = b.ID2 or a.DOB1 = b.DOB2
。但我认为当 ID 不丢失时,DOB 匹配可能会给出一些错误的结果。
您可以先 select 具有两组 ID 的所有行,然后 select DOB 匹配但缺少任一 ID 的所有行。使用 union
将它们放入相同的 table。我现在无法测试我的代码,但是是这样的:
proc sql;
create table final as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1(where=(not missing(ID1)) a
inner join weight2(where=(not missing(ID2)) b
on a.ID1 = b.ID2
union
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
inner join weight2 b
on a.DOB1 = b.DOB2 and (missing(ID1) or missing(ID2))
;
case
表达式可用作连接条件。
不要使用宏。您对 %sysfunc(exist
的使用是错误的, exist
函数检查是否存在数据集,并且 %sysfunc
在源代码编译之前执行,而不是在 SQL 执行时间。
使用 case 表达式计算相等性检查的先决条件。
示例:
data weight1;
input ID1 $ Week1 DOB1;
datalines;
1111 195 101
2222 220 102
3333 173 103
4444 135 104
;
data weight2;
infile datalines missover;
input ID2 $ Week2 DOB2;
datalines;
. 195 101
2222 220 102
3333 173 103
4444 135 104
;
proc sql;
create table want as
select a.ID1, a.DOB1, b.ID2,b.DOB2
from weight1 a
join weight2 b
on case
when (a.id1 is not missing and b.id2 is not missing) then a.id1=b.id2
when (a.dob1 is not missing and b.dob2 is not missing) then a.dob1=b.dob2
else 0
end
;
注意:在真实数据的情况下,每行 table 中有不止一行缺少 id 且出生日期相同,这将导致结果中出现乘法行数效应 table .比如这个样本数据:
1111 195 101
2222 220 102
3333 173 103
4444 135 104
. 145 105 ***
. 175 105 ***
和
. 195 101
2222 220 102
3333 173 103
4444 135 104
. 155 105 ***
. 166 105 ***
4 = 2 x 2 个来自加星标数据的结果行。