数据步骤中的更新语句
update statement in data step
在数据库中,我们有如下电子邮件地址数据集。请注意,id 1003
有两个观察值
data Email;
input id$ email .;
datalines;
1001 1001@gmail.com
1002 1002@gmail.com
1003 1003@gmail.com
1003 2003@gmail.com
;
run;
并且我们收到用户请求更改电子邮件地址,如下所示,
data amendEmail;
input id$ email .;
datalines;
1003 1003@yahoo.com
;
run;
我尝试在数据步骤中使用 update
语句
data newEmail;
update Email amendEmail;
by id;
run;
虽然它只更改了 id 1003 的第一个观察值。
我想要的输出是
1001 1001@gmail.com
1002 1002@gmail.com
1003 1003@yahoo.com
1003 1003@yahoo.com
是否可以使用非 proc sql 方法?
理想情况下,您应该在 by 变量中具有唯一值。如果出现重复,它只会更新第一个观察结果。请参考下面的link
http://support.sas.com/documentation/cdl/en/basess/58133/HTML/default/viewer.htm#a001329152.htm
如果你想更改两行,你最终会得到重复项。您可能应该首先解决来源 table 中的重复问题。
如果您需要具有重复结果的有效解决方案,请考虑使用 PROC SQL 和 LEFT JOIN 以及电子邮件地址的条件子句。
PROC SQL;
CREATE TABLE EGTASK.QUERY_FOR_EMAIL AS
SELECT t1.id,
/* email */
(CASE WHEN t1.id = t2.id THEN t2.email
ELSE t1.email
END) AS email
FROM WORK.EMAIL t1
LEFT JOIN WORK.AMENDEMAIL t2 ON (t1.id = t2.id);
QUIT;
根据评论,如果您更喜欢使用数据步骤,则可以使用以下内容:
data want (drop=email2);
merge Email amendEmail (rename=(email=email2));
by id;
if email2 ne "" then email=email2;
run;
Vasilij 基于合并的数据步骤答案将为您提供您想要的数据集,但不是以最有效的方式,因为它会覆盖整个 email
数据集,而不是只更新您想要的行改变。
您可以使用 modify
语句更改 amendEmail
数据集中具有匹配 ID 的 email
行的电子邮件地址。
首先,您需要确保在 email
数据集中的 id
上有一个索引。这只是一项一次性任务 - 只要您不覆盖 email
数据集(例如,使用另一个不使用 modify
语句的数据步骤,或通过对其进行排序)索引还会在那里。
proc datasets lib = work nolist;
modify email;
index create id;
run;
quit;
现在您可以使用索引进行更新:
data email;
set amendEmail(rename = (email = new_email));
do until(eof);
modify email key = id end = eof;
if _IORC_ then _ERROR_ = 0;
else do;
email = new_email;
replace;
end;
end;
run;
您应该会在日志中看到一些如下所示的输出,表明您的数据集已更新而不是被覆盖:
NOTE: There were 1 observations read from the data set WORK.AMENDEMAIL.
NOTE: The data set WORK.EMAIL has been updated. There were 2 observations rewritten, 0 observations added and 0 observations
deleted.
N.B。在使用这样的 modify
语句之前,请确保已备份主 email
数据集。如果数据步骤被中断,它可能会损坏。
在数据库中,我们有如下电子邮件地址数据集。请注意,id 1003
有两个观察值data Email;
input id$ email .;
datalines;
1001 1001@gmail.com
1002 1002@gmail.com
1003 1003@gmail.com
1003 2003@gmail.com
;
run;
并且我们收到用户请求更改电子邮件地址,如下所示,
data amendEmail;
input id$ email .;
datalines;
1003 1003@yahoo.com
;
run;
我尝试在数据步骤中使用 update
语句
data newEmail;
update Email amendEmail;
by id;
run;
虽然它只更改了 id 1003 的第一个观察值。
我想要的输出是 1001 1001@gmail.com 1002 1002@gmail.com 1003 1003@yahoo.com 1003 1003@yahoo.com
是否可以使用非 proc sql 方法?
理想情况下,您应该在 by 变量中具有唯一值。如果出现重复,它只会更新第一个观察结果。请参考下面的link http://support.sas.com/documentation/cdl/en/basess/58133/HTML/default/viewer.htm#a001329152.htm
如果你想更改两行,你最终会得到重复项。您可能应该首先解决来源 table 中的重复问题。
如果您需要具有重复结果的有效解决方案,请考虑使用 PROC SQL 和 LEFT JOIN 以及电子邮件地址的条件子句。
PROC SQL;
CREATE TABLE EGTASK.QUERY_FOR_EMAIL AS
SELECT t1.id,
/* email */
(CASE WHEN t1.id = t2.id THEN t2.email
ELSE t1.email
END) AS email
FROM WORK.EMAIL t1
LEFT JOIN WORK.AMENDEMAIL t2 ON (t1.id = t2.id);
QUIT;
根据评论,如果您更喜欢使用数据步骤,则可以使用以下内容:
data want (drop=email2);
merge Email amendEmail (rename=(email=email2));
by id;
if email2 ne "" then email=email2;
run;
Vasilij 基于合并的数据步骤答案将为您提供您想要的数据集,但不是以最有效的方式,因为它会覆盖整个 email
数据集,而不是只更新您想要的行改变。
您可以使用 modify
语句更改 amendEmail
数据集中具有匹配 ID 的 email
行的电子邮件地址。
首先,您需要确保在 email
数据集中的 id
上有一个索引。这只是一项一次性任务 - 只要您不覆盖 email
数据集(例如,使用另一个不使用 modify
语句的数据步骤,或通过对其进行排序)索引还会在那里。
proc datasets lib = work nolist;
modify email;
index create id;
run;
quit;
现在您可以使用索引进行更新:
data email;
set amendEmail(rename = (email = new_email));
do until(eof);
modify email key = id end = eof;
if _IORC_ then _ERROR_ = 0;
else do;
email = new_email;
replace;
end;
end;
run;
您应该会在日志中看到一些如下所示的输出,表明您的数据集已更新而不是被覆盖:
NOTE: There were 1 observations read from the data set WORK.AMENDEMAIL.
NOTE: The data set WORK.EMAIL has been updated. There were 2 observations rewritten, 0 observations added and 0 observations
deleted.
N.B。在使用这样的 modify
语句之前,请确保已备份主 email
数据集。如果数据步骤被中断,它可能会损坏。