Re-coding/transforming SQL 值从链接数据到新列:为什么 CASE WHEN 返回多个值?

Re-coding/transforming SQL values into new columns from linked data: why is CASE WHEN returning multiple values?

我处理来自多个 table 的大量链接数据。因此,我 运行 遇到了一些挑战,包括重复数据删除和以更有意义的方式将值重新编码到新列中。

我的核心数据集是一个以行表示的人员级记录列表。但是,链接数据包括每个人的多行,这些数据基于他们被预订参加活动的日期、他们是否出现以及他们是否是我们组织的成员。通常有多个预订。失去会员资格并继续参加 events/cancel/etc 是可能的,但我们感兴趣的是他们是否曾经是会员,如果不是,这是他们与我们组织有过的最高级别的联系。

简而言之:如果他们曾经是会员,则需要优先考虑。

select distinct 
a.ticketnumber
a.id
-- (many additional columns from multiple tables here)
case
when b.Went_Member >=1 then 'Member'
when b.Went_NonMember >=1 then 'Attended but not member'
when b.Going_NonMember >=1 then 'Going but not member'
when b.OptOut='1' then 'Opt Out'
when b.Cancelled >=1 then 'Cancelled'
when c.MemberStatus = '9' then 'Member'
when c.MemberStatus = '6' then 'Attended but not member'
when c.DateBooked > current_timestamp then 'Going but not member'
when c.OptOut='1' then 'Opt out'
when c.MemberStatus = '8' then 'Cancelled'
end [NewMemberStatus]
from table1 a
left join TableWithMemberStatus1 b on a.id = b.id
left join TableWithMemberStatus2 c on a.id = c.id
-- (further left joins to additional tables here)
order by a.ticketnumber

Table b 更准确,因为这些是我们的内部记录,而 table c 来自第三方。恼人的是,C 中的数字与我们决定的顺序不同,所以我不能 select 每个 ID 的最高值。

我的印象是 CASE 在 WHEN 语句的列表中下降,returns 第一个匹配值,但这会产生多行。例如:

ID NewMemberStatus
989898 NULL
989898 Cancelled
777777 Member
111111 Cancelled
111111 Member

我觉得在 ORDER BY 或 GROUP BY 方面可能缺少一些我应该添加的东西?我在里面尝试了 COALESCE 和 CASE 但它没有用。我应该在括号中嵌套一些东西吗?

在您的查询中,您显示了所有行(所有预订),因为没有 WHERE 子句也没有聚合。但是您只希望每个人获得一个结果行。

你想要一个人最好的状态来自于内在table。如果内部 table 中没有此人的条目,您希望他们从第三方 table 获得最佳状态。通过按人汇总内部和第三方 table 中的行,您可以获得最佳状态。然后加入这个人。

我正在使用状态编号,因为这些可以订购(我使用 1 表示最佳状态(会员),所以我寻找最低状态)。最后,我将找到的数字替换为相关文本(例如 'Member' 表示状态 1)。

select
  p.*,
  case coalesce(i.best_status, tp.best_status)
    when 1 then 'Member'
    when 2 then 'Attended but not member'
    when 3 then 'Going but not member'
    when 4 then 'Opt out'
    when 5 then 'Cancelled'
    else 'unknown'
  end as status
from person p
left join
(
  select
    person_id,
    min(case when went_member >= 1 then 1
             when went_nonmember >= 1 then 2
             when going_nonmember >= 1 then 3
             when optout = 1 then 4
             when cancelled >= 1 then 5
        end) as best_status
  from internal_table
  group by person_id
) i on i.person_id = p.person_id
left join
(
  select
    person_id,
    min(case when MemberStatus = 9 then 1
             when MemberStatus = 6 then 2
             when DateBooked > current_timestamp then 3
             when optout = 1 then 4
             when memberstatus = 8 then 5
        end) as best_status
  from thirdparty_table
  group by person_id
) tp on tp.person_id = p.person_id
order by p.person_id;