Оператор sql case на основе количества вхождений

У меня есть таблица (t1) с адресами электронной почты, пользователями и доменными именами:

     email                user         domain
[email protected]        joe123        domain.com
[email protected]         sue234        email.net
      ...                  ...          ...

И еще одна таблица (t2) того, было ли открыто электронное письмо, отправленное на адрес:

  Opened             Email
    0            [email protected]
    1            [email protected]
    0            [email protected]
   ...               ...

Я хотел бы присоединить 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            [email protected]         domain.com
    1            [email protected]          email.net
    0            [email protected]       other 
   ...               ...

но не могу понять соединение (я предполагаю, что это будет левое соединение для создания «другого» значения для редко встречающихся значений) и оператор case, необходимый для соединения значения, если оно встречается более 100 раз, а если не значение ' Другой'.


person screechOwl    schedule 03.11.2014    source источник
comment
Вам нужен having count(*) > 100   -  person crthompson    schedule 04.11.2014


Ответы (3)


Этот подход использует внутренний запрос для получения счетчиков, а затем оператор 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 будет нулевым в том случае, если количество меньше порогового значения. Добавьте немного ISNULL в оператор select для объединения нулей, и вы получите деньги.

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

Ваше здоровье!

person kbrimington    schedule 03.11.2014

Неясно, все ли электронные письма в первой таблице находятся во второй. Если они есть, вы можете сделать:

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;

Ожидайте, что производительность в этой версии будет очень, очень плохой.

person Gordon Linoff    schedule 03.11.2014
comment
Возможно, вы захотите сделать первое условие соединения второго запроса t2.email like '%@' + t1.domain, чтобы разделить поддомены. - person Allan; 04.11.2014
comment
@ Аллан. . . Это имеет большой смысл. Спасибо. Это также влияет на такие вещи, как gmail.com по сравнению с mail.com. - person Gordon Linoff; 04.11.2014

Я думаю, что ниже запрос должен решить вашу проблему

       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
person Navneet    schedule 04.11.2014