在尝试了几种更复杂的方法后,我最终在proc sql 中找到了一种相当简单的方法:
proc sql noprint;
update master a
set status_cd= coalesce(status_cd,
(select status_cd
from transaction b
where a.key= b.key))
where exists (select 1
from transaction b
where a.ABC = b.ABC);
quit;
这将只更新您感兴趣的一列,并且只会更新其键值与交易数据集中匹配的行。
早期尝试:
更通用的 SQL 语法中最明显的一点似乎是this question 的前几个答案中使用的update...set...from...where 模式。但是,目前不支持此语法 - SQL update statement 的文档仅允许 where 子句,而不是 from 子句。
如果您正在对另一个支持此语法的数据库运行直通查询,它可能仍然是一个可行的选择。
或者,有一种方法可以在 SAS 中通过数据步骤执行此操作,前提是主数据集在您的关键变量上建立索引:
/*Create indexed master dataset with some missing values*/
data master(index = (name));
set sashelp.class;
if _n_ <= 5 then call missing(weight);
run;
/*Create transaction dataset with some missing values*/
data transaction;
set sashelp.class(obs = 10 keep = name weight);
if _n_ > 5 then call missing(weight);
run;
data master;
set transaction;
t_weight = weight;
modify master key = name;
if _IORC_ = 0 then do;
weight = coalesce(weight, t_weight);
replace;
end;
/*Suppress log messages if there are key values in transaction but not master*/
else _ERROR_ = 0;
run;
与modify 语句相关的标准警告:如果此数据步骤被中断,则主数据集可能会受到不可挽回的损坏,因此请确保先备份。
在这种情况下,我假设关键变量是唯一的 - 如果不是,则需要稍微复杂一点的数据步骤。
解决proc sql update 语句中缺少from 子句的另一种方法是设置格式合并,例如
data v_format_def /view = v_format_def;
set transaction(rename = (name = start weight = label));
retain fmtname 'key' type 'i';
end = start;
run;
proc format cntlin = v_format_def; run;
proc sql noprint;
update master
set weight = coalesce(weight,input(name,key.))
where master.name in (select name from transaction);
run;
在这种情况下,我在格式定义中使用了type = 'i' 来创建数字信息,proc sql 使用该信息将字符变量name 转换为数字变量weight。根据您的 key 和 status_cd 列是字符还是数字,您可能需要稍微不同地执行此操作。
这种方法在使用该格式时有效地将整个交易数据集加载到内存中,如果您有一个非常大的交易数据集,这可能会出现问题。数据步骤方法几乎不应该使用任何内存,因为它一次只需要加载 1 行。