Join 使用%if%然后%else的Sas宏条件联接

Join 使用%if%然后%else的Sas宏条件联接,join,sas,conditional-statements,sas-macro,Join,Sas,Conditional Statements,Sas Macro,我正在尝试连接两个表,权重1和权重2。 我想先在ID1=ID2上连接这两个表。 如果缺少ID,我将在DOB1=DOB2时加入。 我希望程序比较表中的每一行。 但是sas发现weight2表中缺少第一个ID,然后它完全切换到else语句,并使用DOB1=DOB2进行连接 我的理想结果是将四行连接起来。但是现在sas只给了我三行 data weight1; input ID1 $ Week1 DOB1; datalines; 1111 195 10

我正在尝试连接两个表,权重1和权重2。 我想先在ID1=ID2上连接这两个表。 如果缺少ID,我将在DOB1=DOB2时加入。 我希望程序比较表中的每一行。 但是sas发现weight2表中缺少第一个ID,然后它完全切换到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

如果您信任DOBs上的join与信任IDs上的join一样,那么只需在a.ID1=b.ID2或a.DOB1=b.DOB2上执行
。但我认为当ID没有丢失时,DOB匹配可能会给出一些错误的结果

您可以首先选择具有两组ID的所有行,然后选择DOB匹配且缺少任一ID的所有行。使用
union
将它们放入同一个表中。我现在无法测试我的代码,但类似于以下内容:

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))
;

大小写
表达式可用作联接条件

不要使用宏。使用
%sysfunc(exist
是错误的,
exist
函数检查是否存在数据集,
%sysfunc
是在源代码编译之前执行的,而不是在SQL执行时执行的

使用大小写表达式计算相等性检查的前提条件

例如:

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
  ;
注意:对于实际数据,如果每个表中有多行缺少id且出生日期相同,则会在结果表中产生乘法行计数效应。例如,此示例数据:

1111 195  101
2222 220  102
3333 173  103
4444 135  104
.    145  105 ***
.    175  105 ***     


4=2 x 2结果行来自星号数据。

为什么要测试libref
B
指向的库中是否有名为
ID2
的数据集?您的数据集不是名为WEIGHT1、WEIGHT2等吗?您检查了数据并打印了吗?
WEIGHT2
步骤的第一条
数据线应使用点(
)缺少id2值的占位符。感谢Richard提出此问题。我将添加一个点。感谢您的回答,我无法加入DOB的原因仅是因为DOB列中有时也缺少数据。缺少值不会带来任何问题,因为
final
不会有任何错误匹配的行(如果缺少DOB和ID,缺少的值将给出较小的数据集)。如果所有值都正确(如果不丢失),您可以简单地使用
-方法。否则,如果DOB可能是有害的或非唯一的,因此必须对ID匹配进行优先排序,
联合
方法应该可以工作。非常感谢您的回复!这就是答案!!exist函数检查数据集是否存在,并且%sysfunc在源代码编译之前执行,而不是在SQL执行时执行。"这正是出现错误的原因。当语句像黄金一样工作时的情况。欢迎来到StackOverflow Kailey,确保标记您的问题的答案,并对您找到的关于您搜索的任何问题的有用答案进行投票。感谢您的建议。另一件事是,当方法不是很好时,这种情况下的性能。因为我的数据集非常大(每个表包含大约40万行),查询已经运行了3个小时。您知道提高性能的方法吗?实际的列名称、类型和大小是什么?何时连接条件强制进行外部连接,因此有400k x 400k操作正在进行,如果id值不唯一,结果集中也可能发生许多“复制”(还有一个乘法有效),这会导致大量的“输出”时间写入结果,@RuneS显示的并集方法可能更快,特别是如果数据集有id和dob的索引,并且id是不同的。
.    195  101
2222 220  102
3333 173  103
4444 135  104
.    155  105 ***
.    166  105 ***