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

#mysql

#MySQL

Вопрос:

У меня есть 3 таблицы, tb_orders , tb_tasks amp; tb_userconfig которые я пытаюсь запросить, но кажется, что при выполнении запроса с обоими операторами inner join COUNT() он полностью искажен, однако при попытке выполнить запрос только с одним оператором inner join все, кажется, работает (за вычетом одного столбца, который я бы пропустил)

Пример структуры таблицы:

tb_orders

 | OrderedBy | OrderDate    |
|-----------|--------------|
| persona   | 29/6/21 0:00 |
| persona   | 29/6/21 0:00 |
| personc   | 29/6/21 0:00 |
| personb   | 29/6/21 0:00 |
 

tb_userconfig

 | EmployeeName | Username |
|--------------|----------|
| Person A     | persona  |
| Person B     | personb  |
| Person C     | personc  |
 

tb_tasks

 | AssigneeUser |
|--------------|
| Persom A     |
| Person B     |
| Person C     |
| Person B     |
 

Запрос:

 SELECT T1.EmployeeName, T1.Username, Count(T2.OrderedBy) AS OrderCount, Count(T3.AssigneeUser) AS TaskCount
FROM tb_userconfig AS T1
INNER JOIN (
    SELECT OrderedBy, OrderDate FROM tb_orders
    ) AS T2 on T1.Username = T2.OrderedBy
INNER JOIN (
    SELECT AssigneeUser FROM tb_tasks
    ) AS T3 on T1.EmployeeName = T3.AssigneeUser
GROUP BY T1.EmployeeName ORDER BY T1.EmployeeName
 

Желаемый результат:

 | EmployeeName | Username | OrderCount | TaskCount |
|--------------|----------|------------|-----------|
| Person A     | persona  | 2          | 1         |
| Person B     | personb  | 1          | 2         |
| Person C     | personc  | 1          | 1         |
 

Любые идеи о том, почему оператор приведет к искаженным подсчетам и не даст желаемого результата?

TIA

Комментарии:

1. Можете ли вы добавить искаженный результат?

2. Поскольку это ваш код, он ничего не вернет, потому что предложение ON во 2-м соединении неверно. Это должно быть: on T1.Username = T3.AssigneeUser . Кроме того, для этой выборки данных 2-е соединение не требуется. Итак, я предполагаю, что это не ваш реальный код, и вы слишком упростили свои фактические данные. Опубликуйте код и примеры данных, которые ближе к тому, что у вас есть, и объясните, почему вам нужно 2-е соединение.

3. Ваш код возвращает ошибку, потому sql_mode что по умолчанию используется значение have only_full_group_by (в MySQL 8.0 ), см. DBFIDDLE , который также включает изменение, предлагаемое @forpas, и упрощение того, как выполнять объединения

4. @Luuk спасибо за скрипку, пожалуйста, ознакомьтесь с этим ( dbfiddle.uk /… ). Я удалил personc из tb_tasks, что приводит к искажению результатов подсчета

Ответ №1:

Вы можете упростить, предварительно агрегировав подсчеты.

Не зная ваших данных, я бы предложил использовать внешние соединения и объединяться, чтобы не обрабатывать строки, поскольку в противном случае пользователи с задачами, но без заказов или наоборот, были бы исключены.

 select uc.EmployeeName, uc.username,
  Coalesce(o.OrderCount, 0) OrderCount, 
  Coalesce(t.TaskCount, 0) TaskCount
from tb_userconfig uc
left join (
  select orderedby, Count(*) OrderCount
  from tb_orders
  group by orderedby
) o on o.orderedby=uc.username
left join (
  select AssigneeUser, Count(*) TaskCount
  from tb_tasks
  group by AssigneeUser
) t on t.AssigneeUser=uc.username
 

Демонстрационная скрипка

Комментарии:

1. Спасибо за предложение, однако, когда я пытаюсь его запустить, кажется, что OrderCount он заполняется, однако TaskCount предназначен 0 для всех пользователей… Есть идеи?

2. Пожалуйста, взгляните на эту скрипку DB dbfiddle.uk /…

3. Не совсем уверен, что вы имеете в виду, приведенный выше запрос даже не в вашей скрипке. Когда я использую запрос в своем ответе, в вашей скрипке нет нулей

4. Спасибо, похоже, я делал что-то необычное, но ваш запрос определенно работает! Спасибо за вашу помощь!