【问题标题】:Showing specific results in different columns when self-joining a table in MySQL在 MySQL 中自联接表时在不同列中显示特定结果
【发布时间】:2016-09-26 16:01:46
【问题描述】:

我有一个表 email_activities_2,有一个标题为“action_type”的列,其中结果可以是“sent”、“open”、“click”等,每个 action、每个 email、每个 recipient_id 都有一条记录.例如,recipient_id 54 的 email_id 94607 有两行:第一行的 action_type 是“已发送”,第二行是“打开”。

我想要一个查询,它将在一行中返回,action_type 列列出了两次,但在左边,只显示 action_type = "sent",而右边的列是 action_type = "open" 或 "null"

这是我最接近我想要的:

select email2.email_id, email2.recipient_id, email2.action_type as sent, 
opens.action_type as opened
  from email_activities_2 email2 
  left join email_activities_2 opens on email2.id = opens.id
  where email2.action_type = "sent"
union all
select email2.email_id, email2.recipient_id, email2.action_type as sent, 
opens.action_type as opened
  from email_activities_2 email2
  right join email_activities_2 opens on email2.id = opens.id
  where opens.action_type = "open"
  order by recipient_id, email_id asc;

这会返回:

email_id    |   recipient_id   |  sent  |   opened

94607              54             sent      sent
94607              54             open      open
94981              54             sent      sent
98479              54             sent      sent
98479              54             open      open

当我想要的是:

email_id    |   recipient_id   |  sent  |   opened

94607              54             sent      open
94981              54             sent      NULL
98479              54             sent      open

这可能吗?我是 SQL 的新手,我正在努力解决这个问题。

【问题讨论】:

  • 您想查看“表别名”以创建表的虚拟“副本”,以便可以在查询中使用它两次。如果您有问题,请设置一个小提琴并发布它。

标签: mysql sql mysql-workbench self-join


【解决方案1】:

一种方法是条件聚合,不需要连接。

SELECT e.email_id
     , e.recipient_id
     , MAX(IF(e.action_type='sent',e.action_type,NULL)) AS sent
     , MAX(IF(e.action_type='open',e.action_type,NULL)) AS opened
  FROM email_activities_2 e
 WHERE e.action_type IN ('sent','open')
 GROUP
    BY e.email_id
     , e.recipient_id

GROUP BY 子句会将所有 email_id 和收件人 ID 值相等的行“折叠”成一行。 SELECT 子句中表达式中的条件测试将为每个组“挑选”出'open''sent' 的值。 MAX 聚合将选择返回的最大非 NULL 值,并且仅当组中没有符合条件的行时才返回 NULL。

此查询有可能返回如下一行:

email_id    |   recipient_id   |  sent  |   opened
94999           54                NULL      open

在有open 的行但没有sent 的行的情况下。

如果需要删除这些行,可以添加 HAVING 子句:

HAVING MAX(IF(e.action_type='sent',e.action_type,NULL)) = 'sent'

如果您想从表中返回 email_id 和收件人的所有值,即使没有 action_type 为 'sent''open' 的行,您也可以完全省略 WHERE 子句。

【讨论】:

    【解决方案2】:

    我了解您希望获取所有已发送的电子邮件及其打开的活动(如果它们是打开的) 查询应该是:

    select email2.email_id, email2.recipient_id, email2.action_type as sent, 
    opens.action_type as opened
      from email_activities_2 email2 
      left join (
    select * from  email_activities_2
    where email_activities_2.action_type = "open" 
    ) as opens on email2.id = opens.id
      where email2.action_type = "sent"
    

    【讨论】:

      【解决方案3】:

      以下 SQL 应该可以为您完成这项工作:

      Select email2.email_id,
             email2.recipient_id,
             MAX ( CASE WHEN email2.action_type = "sent" THEN email2.action_type  END ) As sent, 
             MAX (CASE WHEN opens.action_type = "open" THEN opens.action_type  END) As opened
        from email_activities_2 email2 
        left join email_activities_2 opens on email2.id = opens.id
        where email2.action_type = "sent" or opens.action_type = "open"
        group by email2.email_id
        order by recipient_id, email_id asc;
      

      【讨论】:

        【解决方案4】:

        如果您只想显示已发送的电子邮件(或表格仅包含已发送的电子邮件),则 LEFT JOIN 解决方案适用于两种类型。

        select
            sent.email_id,
            sent.recipient_id,
            sent.action_type as sent,
            open.action_type as opened
        from email_activities_2 sent
        left join email_activities_2 open
            on  open.email_id = sent.email_id
            and open.recipient_id = sent.recipient_id
            and open.action_type = 'open'
        where sent.action_type = 'sent';
        

        Demo

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多