【问题标题】:sql case statement based on number of occurrences基于出现次数的sql case语句
【发布时间】:2014-11-03 21:37:17
【问题描述】:

我有一个包含电子邮件地址、用户和域名的表 (t1):

     email                user         domain
joe123@domain.com        joe123        domain.com
sue234@email.net         sue234        email.net
      ...                  ...          ...

还有一张表(t2),显示发送到某个地址的电子邮件是否被打开:

  Opened             Email
    0            joe123@domain.com
    1            sue234@email.net
    0            jack55@mybarber.com
   ...               ...

我想将 t1.domain 加入 t2,但仅限出现次数超过 100 倍的域。

我可以创建一个包含出现次数的表

SELECT domain, count(domain) cntDomain
from table1
group by domain

结果如下:

   domain         cntDomain
 domain.com       5000
 email.net        4300
 mybarber.com     67

生成的表格如下所示:

  Opened             Email                 domain
    0            joe123@domain.com         domain.com
    1            sue234@email.net          email.net
    0            jack55@mybarber.com       other 
   ...               ...

但无法弄清楚连接(我假设它将是一个左连接来为不经常出现的值创建“其他”值),如果它出现超过 100 倍并且如果不是“其他”的值。

【问题讨论】:

  • 你需要一个having count(*) > 100

标签: sql sql-server join case


【解决方案1】:
select *
from table2 t2
inner join
(
    SELECT domain, count(1) cntDomain
    from table1
    group by domain
    having count(1) > 100
) t1 on t2.email = t1.email

【讨论】:

    【解决方案2】:

    此方法使用内部查询来获取计数,然后使用 case 语句将计数解释为域或字符串 'Other'(视情况而定)。在一些播放数据上对其进行了测试,以确保它有效,但我对它的性能没有意见。

    感觉有点尴尬,因为 t1 被查询了两次;一次获得域,再次获得计数。无论如何,它都能完成工作。

    如果特定阈值发生变化,您可以将数字 100 换成另一个数字(或变量)。

    select 
      t2.Opened
    , t2.Email
    , case when t3.cntDomain > 100 then t3.domain else 'Other' end as domain
    from t2
    left outer join t1 on t2.Email = t1.email
    left outer join (
        select t1.domain, count(1) cntDomain
        from t1
        left outer join t2 on t1.email = t2.email
        group by t1.domain
    ) as t3 on t1.domain = t3.domain
    

    编辑

    如果您不喜欢 case 语句,这种方法可能听起来更优雅。使用having 语句修改内部查询。现在,由于左连接,如果计数小于阈值,t3.domain 将为空。在 select 语句中添加一点 ISNULL 以进行空值合并,你就是钱。

    select 
      t2.Opened
    , t2.Email
    , ISNULL(t3.domain, 'Other')
    from t2
    left outer join t1 on t2.Email = t1.email
    left outer join (
        select t1.domain, count(1) cntDomain
        from t1
        left outer join t2 on t1.email = t2.email
        group by t1.domain
        having count(1) > 100
    ) as t3 on t1.domain = t3.domain
    

    干杯!

    【讨论】:

      【解决方案3】:

      尚不清楚第一个表中的所有电子邮件是否都在第二个表中。如果是,您可以这样做:

      select t1.*, t2.domain
      from (select t2.*, count(*) over (partition by domain) as cnt
            from table2 t2
           ) t2 join
           table1 t1
           on t1.email = t2.email
      where cnt > 100;
      

      如果没有,我们可以检查电子邮件地址本身的域:

      select t2.*, t1.domain
      from table2 t2 left join
           (select t1.domain, count(*) as cnt
            from table1 t1
            group by t1.domain
           ) t1
           on t2.email like '%@' + t1.domain and
              cnt > 100;
      

      预计此版本的性能会非常非常糟糕。

      【讨论】:

      • 您可能希望使第二个查询的第一个连接条件t2.email like '%@' + t1.domain 保持子域分开。
      • @Allan 。 . .这很有意义。谢谢你。它还会影响 gmail.commail.com 之类的东西。
      【解决方案4】:

      我认为下面的查询应该可以解决您的问题

             SELECT t2.opened,
             t2.Email,
             CASE WHEN tempt1.email is NULL THEN 'Other' ELSE tempt1.domain END as domain
             FROM t2 LEFT JOIN (SELECT email,domain
             FROM t1
             group by domain HAVING  count(domain)>100) tempt1 on t2.Email=tempt1.email
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-07
        • 2021-03-11
        • 1970-01-01
        • 2015-12-05
        • 1970-01-01
        相关资源
        最近更新 更多