计算来自多个表的联接

问题描述

作为参考,我使用的是Postgres 9.2.23。

我有几个表,其中一个表(user_group)与其他一些表(例如:postsgroup_invites和其他一些表)相关。还有一个groups表,但它不包含我用于这些查询所需的任何数据。

user_groupfk_user_group_id,fk_user_id,fk_group_id,fk_invite_id user_status,...

messagepk_message_id,child_message_id,...

group_prospective_userpk_prospective_user_id,...

我想获取每个相关表的统计信息,以获取指定的组ID列表。 如果 用户是该组的成员。

现在我对每个相关表执行一个查询,例如:

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,6176
  )
  and "public"."user_group"."role" in (
    'ADMINISTRATOR','MEMBER'
  )
  and "public"."user_group"."fk_user_id" = 17517
)
group by "public"."user_group"."fk_group_id"

用于计算组邀请数的查询与上述查询非常相似。只是count whenjoin on发生了变化。

对这些表的每个查询都具有相同的相关逻辑,用于检查当前用户是活动成员的组。有没有一种有效的方法可以将多个类似的查询合并为一个查询

我尝试将多个LEFT JOINselect count distinct一起使用,但是这在具有大量消息和大量邀请的组上遇到了性能问题。有没有一种方法可以轻松/有效地执行子查询

解决方法

@Parfait用户的答案是我能找到的最具扩展性的解决方案。我的查询基于本教程:https://www.sqlteam.com/articles/using-derived-tables-to-calculate-aggregate-values

虽然这并不完美,并且会导致运行一堆子查询,但确实可以一次访问数据库,一次获得所有数据。

它最终像这样:

import sqlite3,json

def dict_factory(cursor,row):
    d = {}
    for idx,col in enumerate(cursor.description):
        # col[0] is the column name
        d[col[0]] = row[idx]
    return d

def get_data_to_json():
    conn = sqlite3.connect("database.db")
    conn.row_factory = dict_factory
    c = conn.cursor()
    c.execute("SELECT * FROM table")
    rst = c.fetchall() # rst is a list of dict
    return jsonify(rst)