【问题标题】:PostgreSQL join subquery can't restrict queryPostgreSQL join 子查询不能限制查询
【发布时间】:2026-02-05 07:20:03
【问题描述】:

将此问题移至 DBA STACKEXCHANGE: https://dba.stackexchange.com/questions/137878/postgresql-join-subquery-cant-restrict-query

我正在开展一个支票拆分项目,该项目拆分某项活动的欠款。用户可以属于多个“组”,每个“组”都有自己的运行余额。

我正在尝试运行一个查询,该查询将返回所有组中单个用户的“欠款”。

目前查询如下所示:

SELECT 
    SUM(owe) 
FROM (
    SELECT 
        (expenses.amount/count(*))
    AS owe 
    FROM expenses 
    LEFT JOIN user_expenses 
    ON (
        expenses.id = user_expenses.expense_id
        ) 
    WHERE expenses.paid_by != 1 
    GROUP BY expenses.id
    ) 
AS total;

问题是此查询全面检索所有费用。我想做的是限制使用:

WHERE user_expenses.user_id = 1

如何将其添加到上述查询(在子查询中)以将结果限制为仅与该用户关联的费用?

表模式(如果可能有帮助的话):

USERS
id
name
username
email

EXPENSES
id
created_at
updated_at
title
amount
group_id
paid_by
img_url
note

USER_EXPENSES (join table)
id
expense_id
user_id

GROUPS
id
created_at
name
desc

USER_GROUPS
id
user_id
group_id

更多示例信息以供澄清: 如果我运行这个查询 -

SELECT 
    e.title,
    e.amount,
    (e.amount/count(*)) AS owe, count(*) AS members 
      FROM expenses e LEFT JOIN
           user_expenses ue
           ON e.id = ue.expense_id
      WHERE e.paid_by != 1 
      GROUP BY e.id;

我得到这样的东西(带有虚拟数据):

如果我运行以下命令:

SELECT 
    e.title,
    e.amount,
    (e.amount/count(*)) AS owe, count(*) AS members 
      FROM expenses e LEFT JOIN
           user_expenses ue
           ON e.id = ue.expense_id AND ue.user_id = 1
      WHERE e.paid_by != 1 
      GROUP BY e.id;

我明白了(注意成员数):

【问题讨论】:

  • 在 user_expense.user_id 上设置条件时,我一直遇到的关键问题是我需要费用中的所有成员返回,以便我可以划分共享费用,如第 5 行所示:@ 987654331@ 希望这是有道理的!

标签: sql postgresql join subquery


【解决方案1】:

如果您的查询有效,那么您只需将其添加到子查询中:

SELECT SUM(owe) 
FROM (SELECT (e.amount/count(*)) AS owe 
      FROM expenses e LEFT JOIN
           user_expenses ue
           ON e.id = ue.expense_id AND ue.user_id = 1
      WHERE expenses.paid_by <> 1 
      GROUP BY expenses.id
     ) t;

【讨论】:

  • 感谢@gordon-linoff 的快速回复。我在最后两行更新了您的建议(将费用替换为别名“e”),查询返回所有费用 - 不仅仅是与用户关联的费用。还有其他想法吗?更新查询:SELECT e.title,e.amount,(e.amount/count(*)) AS owe FROM expenses e LEFT JOIN user_expenses ue ON e.id = ue.expense_id AND ue.user_id = 1 WHERE e.paid_by != 1 GROUP BY e.id;
  • 进一步澄清:使用您建议的附加条件,意味着(e.amount/count(*)) 无法正常运行。该部分返回的费用除以该费用所涉及的人数。
  • 在 WHERE 中添加另一个子查询有意义吗?
【解决方案2】:

我们最终得到了两种解决方案。多亏了一位了不起的团队成员,他通过它提供了动力并做出了一些可行的东西,并且可以认为它更便宜一些。尽管如此,还是要感谢他们。

事实证明 HAVING 是获得所需解决方案的关键部分(感谢 @andriy-m):

HAVING 子句被添加到 SQL 中,因为 WHERE 关键字不能与聚合函数一起使用

SELECT SUM(owe) 
FROM (
  SELECT 
    (e.amount/count(*)) AS owe 
  FROM expenses e 
  LEFT JOIN
       user_expenses ue
  ON e.id = ue.expense_id
  WHERE e.paid_by != 1 
  GROUP BY e.id
  HAVING COUNT(ue.user_id = 1 OR NULL) > 0
) 
AS total;

另外,为了向为此努力的 PJ 致敬:

SELECT SUM(owe) 
FROM (SELECT (expenses.amount/count(*)) AS owe 
FROM expenses 
LEFT JOIN user_expenses ON (expenses.id = user_expenses.expense_id) 
WHERE expenses.paid_by != 1 
AND expense_id IN (select expense_id from users LEFT JOIN user_expenses 
ON (1 = user_expenses.user_id)) GROUP BY expenses.id)
AS total;

【讨论】: