Можно ли использовать два COUNT и два JOIN в запросе SQL из 3 таблиц? - PullRequest
0 голосов
/ 01 марта 2019

Итак, я пытаюсь получить отчет о том, сколько сообщений электронной почты (с приложением, похожим на MailChimp) было отправлено разными пользователями, но мне нужны две разные метрики в одном запросе.Я хочу знать, сколько отдельных писем было отправлено каждым пользователем.Это означает, что если бы они отправляли 3 электронных письма на 100 контактов каждое, то это отображало бы 300. Но я также хочу знать, сколько уникальных электронных писем было отправлено, то есть, это отобразило бы 3.

Я хотел бы получить что-то, что выглядитнапример:

-------------------------------------------------------------
| Full Name   | Username        | Total Sent | Unique Mails |
|-------------|-----------------|------------|--------------|
| John Doe    | jdoe@mail.com   | 12000      | 4            |
| James Smith | jsmith@mail.com | 6000       | 12           |
| Jane Jones  | jjones@mail.com | 4000       | 2            |
| ...         | ...             | ...        | ...          |
-------------------------------------------------------------

Так что я мог знать, что Джон отправляет несколько писем большому количеству контактов, а Джеймс отправляет больше писем меньшему числу контактов.

Вот как выглядит мой запрос.Я изменил имена таблиц и столбцов, но в остальном это точное представление о том, что это такое.

SELECT
    CONCAT(Usernames.FirstName, ' ', Usernames.LastName) AS 'Full Name',
    Usernames.Username,
    COUNT(Sent_Mail_Contacts.IDContact) AS `Total Sent`,
    COUNT(Mass_Mail.IDMass_Mail) AS `Individual E-Mails`
FROM Usernames
LEFT JOIN Sent_Mail_Contacts ON Usernames.Username = Sent_Mail_Contacts.Username
LEFT JOIN Mass_Mail ON Usernames.Username = Mass_Mail.Username
GROUP BY Usernames.Username
ORDER BY `Total Sent`

У меня есть таблица с именами пользователей, таблица с отдельными контактами, по которым достигаются электронные письма, и таблицас уникальными электронными письмами.

Так что мой запрос имеет смысл или нет?Это вообще возможно?Потому что прямо сейчас, когда я запускаю его, он дает мне что-то вроде этого:

-------------------------------------------------------------
| Full Name   | Username        | Total Sent | Unique Mails |
|-------------|-----------------|------------|--------------|
| John Doe    | jdoe@mail.com   | 12000      | 12000        |
| James Smith | jsmith@mail.com | 6000       | 6000         |
| Jane Jones  | jjones@mail.com | 4000       | 4000         |
| ...         | ...             | ...        | ...          |
-------------------------------------------------------------

Я просто даю мне одно и то же число в обоих столбцах и занимает 7 минут для обработки.

ВотПример того, как 3 таблицы будут выглядеть отдельно, если это может помочь:

Usernames
------------------------------------------------
| Username        | FirstName | LastName | ... |
|-----------------|-----------|----------|-----|
| jdoe@mail.com   | John      | Doe      | ... |
| jsmith@mail.com | James     | Smith    | ... |
| jjones@mail.com | Jane      | Jones    | ... |
| ...             | ...       | ...      | ... |
------------------------------------------------

Mass_Mail
----------------------------------------------------
| ID_Mass_Mail | Username       | Date       | ... |
|--------------|----------------|------------|-----|
|            1 | jdoe@mail.com  | 2019-01-16 | ... |
|            2 | jdoe@mail.com  | 2019-01-29 | ... |
|            3 | jjones@mail.com| 2019-02-14 | ... |
|          ... | ...            | ...        | ... |
----------------------------------------------------

Sent_Mail_Contacts
---------------------------------------------------------------------
| ID_Mass_Mail | Username       | Contact_ID | Contact_Email  | ... |
|--------------|----------------|------------|----------------|------
|            1 | jdoe@mail.com  |          1 | bob@mail.com   | ... |
|            1 | jdoe@mail.com  |          2 | jim@mail.com   | ... |
|            1 | jdoe@mail.com  |          3 | cindy@mail.com | ... |
|          ... | ...            |        ... | ...            | ... |
|            2 | jdoe@mail.com  |          4 | mike@mail.com  | ... |
|            2 | jdoe@mail.com  |          2 | jim@mail.com   | ... |
|            2 | jdoe@mail.com  |          3 | cindy@mail.com | ... |
|          ... | ...            |        ... | ...            | ... |
---------------------------------------------------------------------

Ответы [ 4 ]

0 голосов
/ 04 марта 2019

Мне удалось сделать это с помощью запроса, который (кроме изменения фактических имен таблиц и столбцов из-за соображений конфиденциальности) выглядел точно так же.

SELECT
    Accounts.Account_Name AS `account`,
    Usernames.Username AS `username`,
    COUNT(Mass_Mail_Reached_Contacts.ID_Contact) AS `total_emails`,
    COUNT(Mass_Mail_Reached_Contacts.ID_Mass_Mail) / 
        (
            SELECT COUNT(*)
                FROM 
                    Mass_Mail_Reached_Contacts 
                WHERE
                    Mass_Mail_Reached_Contacts.DATE >= '2019-02-01'
                    AND
                    Mass_Mail_Reached_Contacts.DATE <= '2019-02-28'
        )
    * 100 AS `%`,
    COUNT(DISTINCT Mass_Mail.ID_Mass_Mail) AS `unique_emails`,
    COUNT(Mass_Mail_Reached_Contacts.ID_Mass_Mail) / 
        COUNT(DISTINCT mass_mail.ID_Mass_Mail) 
        AS `avg_contacts_per_email`

FROM
    Usernames

LEFT JOIN Mass_Mail_Reached_Contacts ON Mass_Mail_Reached_Contacts.Username = Usernames.Username
LEFT JOIN Account ON Account.ID_Account = Usernames.ID_Account
LEFT JOIN Mass_Mail ON Mass_Mail.ID_Mass_Mail = Mass_Mail_Reached_Contacts.ID_mass_mail

WHERE
    Mass_Mail_Reached_Contacts.DATE >= '2019-02-01'
    AND
    Mass_Mail_Reached_Contacts.DATE <= '2019-02-28'

GROUP BY
    Usernames.Username

HAVING COUNT(DISTINCT Mass_Mail.IDMass_Mail) > 0

ORDER BY
    `total_emails` DESC

Теперь я могу получить таблицуэто выглядит так

Emails Stats
--------------------------------------------------------------------------------------
| account  | username     | total_emails |     % | unique_emails | avg_contact_email | 
|----------|--------------|--------------|-------|------------------------------------
| Bob inc. | bob@mail.com | 28,550       | 14.52 |            12 |           2379.17 |
| ...      | ...          | ...          |   ... |           ... |               ... |
--------------------------------------------------------------------------------------
0 голосов
/ 02 марта 2019

Если значения в IDMass_Mail указывают на уникальный адрес электронной почты, то вам просто нужно отредактировать последний COUNT для использования ключевого слова DISTINCT.

COUNT(DISTINCT Mass_Mail.IDMass_Mail) AS `Individual E-Mails`

Это вернет номер уникальногозначения в группировке по Username.

Вы также должны получить повышение производительности, если сможете добавлять индексы к столбцам Username в таблицах Sent_Mail_Contacts и Mass_Mail.

0 голосов
/ 02 марта 2019

Для начала: Почему Mass_Mail и Sent_Mail_Contacts оба содержат Username?Это выглядит излишним.Или Sent_Mail_Contacts.ID_Mass_Mail nullable?

По крайней мере, для этого запроса, я полагаю, мы можем полностью игнорировать Username в Sent_Mail_Contacts.Что действительно связывает две таблицы, так это ID_Mass_Mail, и вы забыли этот критерий соединения в своем запросе.

select
  ws_concat(' ', u.firstname, u.lastname) as full_name,
  u.username,
  count(smc.idmass_mail) as total_sent,
  count(mm.idmass_mail) as individual_e_mails
from usernames u
left join mass_mail mm on mm.username = u.username
left join sent_mail_contacts smc on smc.id_mass_mail = u.id_mass_mail
group by u.username
order by total_sent;
0 голосов
/ 01 марта 2019

Использовать COUNT(DISTINCT ...):

SELECT
    CONCAT(Usernames.FirstName, ' ', Usernames.LastName) AS 'Full Name',
    Usernames.Username,
    COUNT(Sent_Mail_Contacts.IDContact) AS `Total Sent`,
    COUNT(DISTINCT Mass_Mail.IDMass_Mail) AS `Individual E-Mails`
FROM Usernames
LEFT JOIN Sent_Mail_Contacts ON Usernames.Username = Sent_Mail_Contacts.Username
LEFT JOIN Mass_Mail ON Usernames.Username = Mass_Mail.Username
GROUP BY Usernames.Username
ORDER BY `Total Sent`

Примечание: это не сделает запрос быстрее.Для начала вы должны по крайней мере убедиться, что вы используете отношения первичного / внешнего ключей в JOIN s: Usernames(Username), Sent_Mail_Contacts(Username), Mass_Mail(Username)

...