计数来自多个表的连接
Count Joins from Multiple Tables
作为参考,我使用的是 Postgres 9.2.23。
我有几个 table,其中一个 table (user_group
) 与其他一些 table 相关(例如:posts
、group_invites
,还有一些其他的)。还有一个 groups
table,但它不包含我进行这些查询所需的任何数据。
Tableuser_group
:
fk_user_group_id, fk_user_id, fk_group_id, fk_invite_id user_status, ...
Tablemessage
:
pk_message_id, fk_user_id, fk_group_id, child_message_id, ...
Tablegroup_prospective_user
:
pk_prospective_user_id, fk_group_id, ...
我想为指定组 ID 列表的每个相关 table 获取一些统计信息 if该用户是该组的成员。
现在我对每个相关 table 进行一个查询,例如:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "numDiscussions",
count("public"."message"."pk_message_id") as "numDiscussionPosts"
from "public"."user_group"
left outer join "public"."message"
on "public"."message"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 1070
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
以及邀请:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when "public"."prospective_user"."status" = 1 then "public"."prospective_user"."pk_prospective_user_id"
end) as "numInviteesExternal"
from "public"."user_group"
left outer join "public"."prospective_user"
on "public"."prospective_user"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 6176
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
统计群组邀请数的查询与上述查询非常相似。只是 count when
和 join on
发生了变化。
对这些 table 的每个查询都具有相同的相关逻辑,用于检查当前用户是活跃成员的组。有没有有效的方法将多个类似的查询合并为一个查询?
我尝试将多个 LEFT JOIN
与 select count distinct
一起使用,但是 运行 在具有大量消息和大量邀请的群组中出现性能问题。有没有办法 easily/efficiently 使用子查询来做到这一点?
用户@Parfait 的回答是我能找到的最具扩展性的解决方案。我的查询基于本教程:https://www.sqlteam.com/articles/using-derived-tables-to-calculate-aggregate-values.
虽然这并不完美,并且会导致一堆子查询 运行,但它确实一次获取了所有数据,而且只需要访问数据库一次。
结果是这样的:
"groups"."groupId",
coalesce(
"members"."member_count",
0
) as "numActiveMembers",
coalesce(
"members"."invitee_count",
0
) as "numInviteesInternal",
coalesce(
"discussions"."discussions_count",
0
) as "numDiscussions",
coalesce(
"discussions"."posts_count",
0
) as "numDiscussionPosts"
from (
select "public"."user_group"."fk_group_id" as "groupId"
from "public"."user_group"
where (
"public"."user_group"."fk_group_id" in (
1, 2, 3, 4, 5
)
and "public"."user_group"."role" = 'ADMINISTRATOR'
and "public"."user_group"."fk_user_id" = 123
)
group by "public"."user_group"."fk_group_id"
) as "groups"
left outer join (
select
"public"."user_group"."fk_group_id" as "members_group_id",
count(distinct case
when "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
) then "public"."user_group"."pk_user_group_id"
end) as "member_count",
count(distinct case
when "public"."user_group"."role" = 'INVITEE' then "public"."user_group"."pk_user_group_id"
end) as "invitee_count"
from "public"."user_group"
group by "public"."user_group"."fk_group_id"
) as "members"
on "members_group_id" = "groupId"
left outer join (
select
"public"."message"."fk_group_id" as "discussions_group_id",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "discussions_count",
count("public"."message"."pk_message_id") as "posts_count"
from "public"."message"
group by "public"."message"."fk_group_id"
) as "discussions"
on "discussions_group_id" = "groupId"```
作为参考,我使用的是 Postgres 9.2.23。
我有几个 table,其中一个 table (user_group
) 与其他一些 table 相关(例如:posts
、group_invites
,还有一些其他的)。还有一个 groups
table,但它不包含我进行这些查询所需的任何数据。
Tableuser_group
:
fk_user_group_id, fk_user_id, fk_group_id, fk_invite_id user_status, ...
Tablemessage
:
pk_message_id, fk_user_id, fk_group_id, child_message_id, ...
Tablegroup_prospective_user
:
pk_prospective_user_id, fk_group_id, ...
我想为指定组 ID 列表的每个相关 table 获取一些统计信息 if该用户是该组的成员。
现在我对每个相关 table 进行一个查询,例如:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "numDiscussions",
count("public"."message"."pk_message_id") as "numDiscussionPosts"
from "public"."user_group"
left outer join "public"."message"
on "public"."message"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 1070
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
以及邀请:
select
"public"."user_group"."fk_group_id" as "groupId",
count(case
when "public"."prospective_user"."status" = 1 then "public"."prospective_user"."pk_prospective_user_id"
end) as "numInviteesExternal"
from "public"."user_group"
left outer join "public"."prospective_user"
on "public"."prospective_user"."fk_group_id" = "public"."user_group"."fk_group_id"
where (
"public"."user_group"."fk_group_id" in (
1, 11, 23, 530, 6176
)
and "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
)
and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"
统计群组邀请数的查询与上述查询非常相似。只是 count when
和 join on
发生了变化。
对这些 table 的每个查询都具有相同的相关逻辑,用于检查当前用户是活跃成员的组。有没有有效的方法将多个类似的查询合并为一个查询?
我尝试将多个 LEFT JOIN
与 select count distinct
一起使用,但是 运行 在具有大量消息和大量邀请的群组中出现性能问题。有没有办法 easily/efficiently 使用子查询来做到这一点?
用户@Parfait 的回答是我能找到的最具扩展性的解决方案。我的查询基于本教程:https://www.sqlteam.com/articles/using-derived-tables-to-calculate-aggregate-values.
虽然这并不完美,并且会导致一堆子查询 运行,但它确实一次获取了所有数据,而且只需要访问数据库一次。
结果是这样的:
"groups"."groupId",
coalesce(
"members"."member_count",
0
) as "numActiveMembers",
coalesce(
"members"."invitee_count",
0
) as "numInviteesInternal",
coalesce(
"discussions"."discussions_count",
0
) as "numDiscussions",
coalesce(
"discussions"."posts_count",
0
) as "numDiscussionPosts"
from (
select "public"."user_group"."fk_group_id" as "groupId"
from "public"."user_group"
where (
"public"."user_group"."fk_group_id" in (
1, 2, 3, 4, 5
)
and "public"."user_group"."role" = 'ADMINISTRATOR'
and "public"."user_group"."fk_user_id" = 123
)
group by "public"."user_group"."fk_group_id"
) as "groups"
left outer join (
select
"public"."user_group"."fk_group_id" as "members_group_id",
count(distinct case
when "public"."user_group"."role" in (
'ADMINISTRATOR', 'MODERATOR', 'MEMBER'
) then "public"."user_group"."pk_user_group_id"
end) as "member_count",
count(distinct case
when "public"."user_group"."role" = 'INVITEE' then "public"."user_group"."pk_user_group_id"
end) as "invitee_count"
from "public"."user_group"
group by "public"."user_group"."fk_group_id"
) as "members"
on "members_group_id" = "groupId"
left outer join (
select
"public"."message"."fk_group_id" as "discussions_group_id",
count(case
when (
"public"."message"."child_message_id" is null
and "public"."message"."pk_message_id" is not null
) then "public"."message"."pk_message_id"
end) as "discussions_count",
count("public"."message"."pk_message_id") as "posts_count"
from "public"."message"
group by "public"."message"."fk_group_id"
) as "discussions"
on "discussions_group_id" = "groupId"```