如何在具有条件的 2nd table 上使用 Group by 时从左侧 Table 检索所有数据

How to retrieve all the data from the Left Table while using Group by on 2nd table with Having Condition

考虑三个表,

  1. 团队
  2. 成员(每个成员属于某个团队)
  3. 任务(每个任务由某个成员执行)

任务Table

t_id      member_id
1       1
2       1 
3       2
4       1

会员Table

id      name      team_id
1       Ali       1
2       Khalil    1
3       Bilal     1
4       John      2
5       Smith     2

现在我想要的结果是特定团队Table成员的完整详细信息以及每个成员执行的总任务数。

为了解决这个问题,我写了这个查询,

select m.*, count(t.member_id) as 'Tasks' 
from tbl_member m 
left join tbl_task t on m.m_id = t.member_id 
group by t.member_id 
having m.team_id = :team_id

其中 team_id 可以是用户给定的任何变量。

当我 运行 这个查询 team_id = 1 时,我得到了这些结果(只打印成员姓名和他的总任务)

m_name     Tasks
    Ali     3
    Khalil  1 

如您所见,它跳过了 Bilal,他也是 Team_ID = 1 的一部分,但因为他执行了 0 个任务,它不打印 Bilal(即使我使用 left join

同样,如果我使用 Team_ID = 2,我会得到这些结果,

  m_name     Tasks
    John     0
    

它现在打印 John(完成 0 个任务)但不打印 Smith,他也是 Team 2 的一员但没有完成任何任务。

所以,基本上,查询缺少所有完成 0 个任务的人(除非所有团队成员都完成了 0 个任务。在这种情况下,它只打印该团队的第一个成员并跳过另一个,就像 Team ID = 2)

谁能告诉我如何解决这个问题?我想打印一个团队的所有成员及其计数,即使他们的任务总数为零。 请注意,这不是强制性的,必须使用联接来完成。这也可以用子查询来完成,但同样,我也无法用子查询做出正确的逻辑。

您的 GROUP BYHAVING 正在撤消 LEFT JOIN。试试这个:

select m.*, count(t.member_id) as Tasks
from tbl_member m left join
     tbl_task t
     on m.m_id = t.member_id and
        m.team_id = :team_id
group by m.m_id;

按左侧 table 列分组,m.id ..

select m.*, count(t.member_id) as 'Tasks' 
from tbl_member m 
left join tbl_task t on m.id = t.member_id 
where m.team_id = :team_id
group by m.id, m.name, m.team_id

我正在使用您 table 定义中的列名。您的查询使用不同的命名。根据需要进行更正。

您可以使用子查询来获取完成的任务数,而无需任何左连接或 group by 子句。

DB-Fiddle:

架构和插入语句:

 create table tbl_task(t_id int,      member_id int);
 insert into tbl_task values(1,       1);
 insert into tbl_task values(2,       1); 
 insert into tbl_task values(3,       2);
 insert into tbl_task values(4,       1);

 create table tbl_member(id int, name varchar(100),      team_id int);
 insert into tbl_member values(1,       'Ali'       ,1);
 insert into tbl_member values(2,       'Khalil'    ,1);
 insert into tbl_member values(3,       'Bilal'     ,1);
 insert into tbl_member values(4,       'John'      ,2);
 insert into tbl_member values(5,       'Smith'     ,2);

查询:

 select m.*,(select count(t_id)from tbl_task t where t.member_id=m.id)  as 'Tasks' 
 from tbl_member m 
 where m.team_id=1

输出:

id name team_id Tasks
1 Ali 1 3
2 Khalil 1 1
3 Bilal 1 0

db<>fiddle here

戈登的回答当然是正确的。但是,您可以采用另一种方法。涉及到这个子查询来统计任务。

        select member_id, count(*) numb
          from tbl_task
         group by member_id

然后你离开加入你的成员table。

select m.*, t.numb as 'Tasks' 
 from tbl_member m 
 left join (  select member_id, count(*) numb
                 from tbl_task
                group by member_id
           ) t on m.m_id = t.member_id 
 where m.team_id = :team_id

此查询模式使用 main LEFT JOIN aggregate 模式,其中 aggregate table 包含对应于 main table 的零行或一行。您可能会从尚未完成任何任务的团队成员那里获得一些 NULL 值。您可以使用 COALESCE() 解决该问题。

select m.*, COALESCE(t.numb, 0) as 'Tasks' 

我写这篇文章是因为我发现 main LEFT JOIN aggregate 模式对于各种报告查询非常有用。例如,您可能需要它来按成员从两个不同的 table 中获取聚合。如果您不使用该模式,您将获得组合爆炸和高数字。这是一个计算缺勤和任务的示例。

select m.*, t.numb as 'Tasks', a.numb as 'Absences'
 from tbl_member m 
 left join (  select member_id, count(*) numb
                 from tbl_task
                group by member_id
           ) t on m.m_id = t.member_id 
 left join (  select member_id, count(*) numb
                 from tbl_absence
                group by member_id
           ) a on m.m_id = t.member_id 
 where m.team_id = :team_id

您的原始查询无法正常工作,因为您可以通过在 WHERE 或 HAVING 子句中提及第二个 table 中的列将 LEFT JOIN 转换为普通 JOIN。那是因为 NULL = valueNULL <> value always 都是假的,所以除了 WHERE (col IS NULL OR col = val) 之外的任何 WHERE 标准都不会被满足。