如何解决“case when”出错
我想创建一个列“治愈”,当客户在have1
出现后的当天或随后两天离开 have2
时取值为 1 .数据 have1
是定义客户端何时进入和离开特定状态的数据集。 have2
显示联系客户的时间。
这是我制作的代码:
proc SQL;
create table want2 as
select b.*,case when b.Outcome = "Answered" or
b.Outcome = "Answerphone Message Left" or
b.Outcome = "Answerphone Message Not Left" or
b.Outcome = "No Answer"
and
a.Start_date <= b.Date <= a.End_date
and
a.End_date <= b.Date+2
then 1 else 0 END as Cured
from have1 a,have2 b
where a.ID=b.ID;
quit;
我正在使用的数据集是:
data have1;
infile datalines dlmstr=' | ';
input ID Start_date :ddmmyy10. End_date :ddmmyy10.;
format date start_date date9.;
datalines;
ID | Start_date | End_date
1 | 01/01/2021 | 03/01/2021
1 | 20/01/2021 | 21/01/2021
2 | 05/01/2021 | 07/01/2021
3 | 10/01/2021 | 30/01/2021
3 | 25/01/2021 | 25/01/2021
;;;
run;
data have2;
infile datalines dlmstr=' | ';
input ID Date :ddmmyy10. Outcome ;
format Date date9.;
datalines;
ID | Date | Outcome
1 | 01/01/2021 | Answered
2 | 05/01/2021 | Asnwerphone Message Left
3 | 12/01/2021 | Answerphone Message Left
3 | 25/01/2021 | No Answer
;;;
run;
在这种情况下,我应该得到以下信息:
ID | Date | Outcome | Cured
1 | 01/01/2021 | Answered | 1
2 | 05/01/2021 | Asnwerphone Message Left | 1
3 | 12/01/2021 | Answerphone Message Left | 0
3 | 25/01/2021 | No Answer | 1
ID1 痊愈了,因为他在 01/01 后离开了 have1
2 天
ID2 也治愈了,因为他们在 05/01 后离开了 have1
2 天
ID3 没有治愈,因为他们在 12/01 后离开了 have1
超过 15 天
ID3 治愈,因为他们在同一天离开了 have1
这是该代码的结果:
ID| Date | Outcome | Cured
1 01JAN2021 Answered 1
1 01JAN2021 Answered 0
2 05JAN2021 Asnwerph 0
3 12JAN2021 Answerph 0
3 25JAN2021 No Answe 0
3 12JAN2021 Answerph 0
3 25JAN2021 No Answe 1
这是不对的:首先它重复了观察,但它没有准确地选择那些在 Cured (ID 2) 中应该为 1 的观察。
知道什么可能是错误/遗漏的吗?
解决方法
我怀疑你想要:
bin
我还想知道您是否真的想要笛卡尔积。通常,您希望 select b.*,(case when b.Outcome in ('Answered','Answerphone Message Left','Answerphone Message Not Left','No Answer') and
a.Start_date <= b.Date and
b.Date < a.End_date and
a.End_date <= b.Date+2
then 1 else 0
end) as Cured
具有特定的 join
条件。
在任何编程代码中(SAS 和 SQL 之外),无论何时将 PosixPath
与 OR
一起使用,始终用括号分隔条件:
AND
更好的是,使用 CASE
WHEN (b.Outcome = "Answered" OR
b.Outcome = "Answerphone Message Left" OR
b.Outcome = "Answerphone Message Not Left" OR
b.Outcome = "No Answer")
AND
(a.Start_date <= b.Date < a.End_date)
AND
(a.End_date <= b.Date+2)
THEN 1
ELSE 0
END AS Cured
运算符来收集值并避免使用 IN
:
OR
,
如果该 ID 的任何结束日期符合您的条件,您似乎想对结果进行分组并设置 CURED=1。所以使用 MAX() 聚合函数。
我不确定您为什么要测试 OUTCOME 的值,因为您的示例中没有未包含在要测试的值列表中的值。
data have1;
input ID Start_date :yymmdd. End_date :yymmdd.;
format Start_date End_date yymmdd10.;
datalines4;
1 2021-01-01 2021-01-03
1 2021-01-20 2021-01-21
2 2021-01-05 2021-01-07
3 2021-01-10 2021-01-30
3 2021-01-25 2021-01-25
;;;;
data have2;
input ID Date :yymmdd. Outcome $40.;
format Date yymmdd10.;
datalines4;
1 2021-01-01 Answered
2 2021-01-05 Answerphone Message Left
3 2021-01-12 Answerphone Message Left
3 2021-01-25 No Answer
4 2021-01-25 No Answer
;;;;
proc SQL;
create table want2 as
select b.id,b.date,b.outcome,max(
case when (a.Start_date <= b.Date <= a.End_date)
and (a.End_date <= b.Date+2) then 1
else 0
end
) as Cured
from have1 a
right join have2 b
on a.id=b.id
group by b.id,b.outcome
;
quit;
结果:
Obs ID Date Outcome Cured
1 1 2021-01-01 Answered 1
2 2 2021-01-05 Answerphone Message Left 1
3 3 2021-01-12 Answerphone Message Left 0
4 3 2021-01-25 No Answer 1
5 4 2021-01-25 No Answer 0
PS 以 D-M-Y 或 M-D-Y 顺序显示日期只会让您的一半观众感到困惑。
,复杂的逻辑通常需要括号来正确地对表达式进行分组。
SQL 逻辑运算符 AND
的优先级高于 OR
线性编码的逻辑语句,例如
P OR Q or R OR S AND X AND Y AND Z
评估为
P or Q or R or (((S and X) and Y) and Z)
并且一般需要修正为
(P OR Q or R OR S) AND X AND Y AND Z
如@Parfait 所述,当 IN
P
Q
R
都是处理匹配单个字符变量的表达式时,您可以使用 S
运算符许多不同的术语。使用 IN:
匹配术语前缀。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。