将 SQL 值从链接数据重新编码/转换为新列:为啥 CASE WHEN 返回多个值?

Posted

技术标签:

【中文标题】将 SQL 值从链接数据重新编码/转换为新列:为啥 CASE WHEN 返回多个值?【英文标题】:Re-coding/transforming SQL values into new columns from linked data: why is CASE WHEN returning multiple values?将 SQL 值从链接数据重新编码/转换为新列:为什么 CASE WHEN 返回多个值? 【发布时间】:2021-09-27 18:31:39 【问题描述】:

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

我的核心数据集是行的个人级别记录列表。但是,链接的数据包括每人多行,具体取决于他们被预订参加活动的日期、他们是否出现以及他们是否是我们组织的成员。通常有多个预订。可能会失去会员身份并继续参加活动/取消/等,但我们对他们是否曾经是会员感兴趣,如果不是,这是他们与我们组织的***别联系。

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

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

表 b 更准确,因为这些是我们的内部记录,而表 c 来自第三方。烦人的是,C 中的数字与我们决定的有意义的顺序不同,所以我不能让它为每个 ID 选择最大值。

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

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

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

【问题讨论】:

这不是“生成”额外行的情况...在这里您将获得表 A、B 和 C 行。 “CASE 沿着 WHEN 语句的列表向下移动并返回第一个匹配值” - 完全正确。多行由连接产生,而不是大小写。 I tried COALESCE with CASE inside 怎么样?你能展示你尝试了什么吗? and it didn't work. 这是什么意思?如果我通过电话告诉我的机械师我的车坏了,他们会挂断我的电话。 看起来您想按 ID 对当前输出进行分组并获得某种 Max(NewMemberStatus_priority)。 【参考方案1】:

在您的查询中,您将显示所有行(所有预订),因为没有 WHERE 子句并且没有聚合。但您只需要每人一个结果行。

您希望从内部表中获得一个人的最佳状态。如果内部表中没有人员的条目,则您希望从第三方表中获得最佳状态。通过按人聚合内部和第三方表中的行,您可以获得最佳状态。然后加入这个人。

我使用状态编号,因为这些可以订购(我使用 1 表示最佳状态(成员),所以我寻找最低状态)。最后,我将找到的数字替换为相关文本(例如状态 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;

【讨论】:

以上是关于将 SQL 值从链接数据重新编码/转换为新列:为啥 CASE WHEN 返回多个值?的主要内容,如果未能解决你的问题,请参考以下文章

使用火花将每行中的值转换为新列

将 Pyspark Dataframe 列从数组转换为新列

将向量合并为 df,并将向量名称转换为新列的行

Oracle SQL - 如何将多列合并为新列

SQL 动态地将值拆分为新列

如何将 Pandas DataFrame 中字典的字符串表示形式转换为新列?