Двойной счет при присоединении к PostgreSQL - PullRequest
0 голосов
/ 10 января 2019

У меня есть следующие таблицы:

пользователи со следующими столбцами:

id: INT
name: VARCHAR
boss_id: INT

боссы со следующими столбцами:

id: INT
name: VARCHAR

сообщения со следующими столбцами:

author_id: INT (reference to users)
body: VARCHAR
type: VARCHAR

messages_targets со следующими столбцами:

user_id: INT (reference to users)
message_id: INT (reference to messages)

Теперь у меня есть следующий запрос, который правильно возвращает мне для каждого из боссов, процент пользователей, которые получили по крайней мере одно сообщение типа 'срочно' Вот как я сделал запрос:

SELECT (COUNT(DISTINCT CASE WHEN messages.type = 'urgent' THEN users.id END)::float / NULLIF(COUNT(DISTINCT users.id)::float, 0)) * 100,
bosses.id
FROM bosses
LEFT JOIN users ON users.boss_id = bosses.id
LEFT JOIN messages_targets ON messages_targets.user_id = users.id
LEFT JOIN messages ON messages.id = messages_targets.message_id
GROUP BY bosses.id

Теперь я хочу изменить этот запрос, чтобы он также возвращал мне количество срочных сообщений, созданных пользователями, сгруппированных по их боссу. Итак, я попробовал это:

SELECT (COUNT(DISTINCT CASE WHEN messages.type = 'urgent' THEN users.id END)::float / NULLIF(COUNT(DISTINCT users.id)::float, 0)) * 100 as percentage_received,
COUNT(CASE WHEN authored_messages.type = 'urgent' THEN 1 END) authored_messages_count
bosses.id
FROM bosses
LEFT JOIN users ON users.boss_id = bosses.id
LEFT JOIN messages_targets ON messages_targets.user_id = users.id
LEFT JOIN messages ON messages.id = messages_targets.message_id
LEFT JOIN messages authored_messages ON messages.author_id = users.id
GROUP BY bosses.id

Но это не работает. Кажется, это двойной учет некоторых данных.

Вот некоторые примерные данные, следующие за тем, что я ожидал:

bosses (id, name)
1, John
2, Charles

users (id, name, boss_id)
1, Mai, 1
2, Donald, 1
3, Denver, 2

messages (author_id, body, type)
1, 'message from Mai to Donald', 'urgent'
2, 'message from Donald to Denver', 'normal'
3, 'message from Denver to Mai', 'urgent'
4, 'message from Mai to Donald', 'urgent'

messages_targets (user_id, message_id)
2, 1
3, 2
1, 3 
2, 4

Я ожидал бы получить следующее:

boss_id, percentage_received, authored_messages

1, 100, 2 # (Both Mai and Donald received urgent messages, and in total there were 2 urgent messages sent)
2, 0, 1 # (Denver did not receive any urgent messages, but he sent one message)

1 Ответ

0 голосов
/ 10 января 2019

Попробуйте следующий запрос. Он сохраняет два агрегата отдельно, поэтому их объединения не должны влиять друг на друга

SELECT 
    (
        SELECT 
           COUNT(DISTINCT CASE WHEN messages.type = 'urgent' THEN users.id END)::float / 
           NULLIF(COUNT(DISTINCT users.id)::float, 0)) * 100 
        FROM users
        JOIN messages_targets ON messages_targets.user_id = users.id
        JOIN messages ON messages.id = messages_targets.message_id
        WHERE users.boss_id = bosses.id
    ) percentage_received,
    (
        SELECT 
            COUNT(CASE WHEN messages.type = 'urgent' THEN 1 END) authored_messages_count
        FROM users
        JOIN messages_targets ON messages_targets.user_id = users.id
        JOIN messages ON messages.author_id = users.id
        WHERE users.boss_id = bosses.id
    ) authored_messages_count
    bosses.id
FROM bosses
...