如何在具有条件的 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
考虑三个表,
- 团队
- 成员(每个成员属于某个团队)
- 任务(每个任务由某个成员执行)
任务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 BY
和 HAVING
正在撤消 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 = value
和 NULL <> value
always 都是假的,所以除了 WHERE (col IS NULL OR col = val)
之外的任何 WHERE 标准都不会被满足。
考虑三个表,
- 团队
- 成员(每个成员属于某个团队)
- 任务(每个任务由某个成员执行)
任务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 BY
和 HAVING
正在撤消 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 = value
和 NULL <> value
always 都是假的,所以除了 WHERE (col IS NULL OR col = val)
之外的任何 WHERE 标准都不会被满足。