Используя SQL, как я могу улучшить подсчет частот только тех пар, которые встречаются взаимно в обоих столбцах - PullRequest
0 голосов
/ 19 апреля 2020

Можно ли улучшить мое решение?

У меня есть несколько таблиц:

отправители: (Примечание: email_id является первичный ключ)

| email_id | sender_id |
|----------|-----------|
| 1        | 80        |
| 2        | 80        |
| 3        | 80        |
| 4        | 80        |
| 5        | 87        |

приемники

| email_id | receiver_id |
|----------|-------------|
| 1        | 87          |
| 2        | 185         |
| 3        | 185         |
| 3        | 232         |
| 4        | 87          |
| 5        | 80          |

Желаемый выход

| A  | B  | Frequency |
|----|----|-----------|
| 80 | 87 | 3         |

Вот мое текущее решение:

with g as (
    select
        s.sender_id as Sender,
        r.receiver_id as Receiver,
        count(*) as Frequency
    from receivers r, senders s
    where s.email_id = r.email_id
    group by Sender, Receiver
)
select
    g1.Sender as A,
    g1.Receiver as B,
    g1.Frequency + g2.Frequency as Frequency
from g g1, g g2
where g1.Sender = g2.Receiver 
    and g1.Receiver = g2.Sender
    and A < B
order by Frequency desc
;

Что касается баз данных: я ищу ANSI-совместимое решение, которое будет работать в разных базах данных.

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Если я правильно понимаю, вы хотите считать письма независимо от направления. В данных вашего примера каждое письмо имеет только одного получателя. Если это так, вы можете сделать:

select min(s.sender_id, r.receiver_id) as a, 
       max(s.sender_id, r.receiver_id) as b,
       count(*) as frequency
from senders s inner join
     receivers r
     on r.email_id = s.email_id
group by min(s.sender_id, r.receiver_id), max(s.sender_id, r.receiver_id) 
order by frequency desc;

SQLite использует min() и max() с несколькими аргументами для того, что другие базы данных используют least() и greatest() для.

1 голос
/ 19 апреля 2020

Я думаю, что вы хотите least() и greatest() - если ваша база данных поддерживает их:

select
    least(s.sender_id, r.receiver_id) a, 
    greatest(s.sender_id, r.receiver_id) b,
    count(*) frequency
from senders s
inner join receivers r on r.email_id = s.email_id
group by least(s.sender_id, r.receiver_id), greatest(s.sender_id, r.receiver_id)
order by frequency desc

В SQLite эквивалентными функциями являются min() и max():

select
    min(s.sender_id, r.receiver_id) a, 
    max(s.sender_id, r.receiver_id) b,
    count(*) frequency
from senders s
inner join receivers r on r.email_id = s.email_id
group by min(s.sender_id, r.receiver_id), max(s.sender_id, r.receiver_id)
order by frequency desc

Демонстрация на DB Fiddle :

 a |   b | frequency
-: | --: | --------:
80 |  87 |         3
80 | 185 |         2
80 | 232 |         1

Если вы хотите фильтровать только по кортежам, имеющим двустороннюю связь, Вы можете добавить предложение having к запросу:

select
    min(s.sender_id, r.receiver_id) a, 
    max(s.sender_id, r.receiver_id) b,
    count(*) frequency
from senders s
inner join receivers r on r.email_id = s.email_id
group by min(s.sender_id, r.receiver_id), max(s.sender_id, r.receiver_id)
having min(s.sender_id) <> max(s.sender_id)
order by frequency desc
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...