【问题标题】:Selecting Aggregate from a Child Table从子表中选择聚合
【发布时间】:2018-08-10 17:22:27
【问题描述】:

我有这三个表:

CREATE TABLE users (
  user_id INT NOT NULL PRIMARY KEY
);

CREATE TABLE accounts (
  account_id INT NOT NULL PRIMARY KEY,
  user_id INT NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users (user_id)
);

CREATE TABLE payments (
  payment_id INT NOT NULL,
  account_id INT NOT NULL,
  amount DECIMAL(9,2) NOT NULL,
  extra_charge TINYINT(1) NOT NULL DEFAULT 0,
  FOREIGN KEY (account_id) REFERENCES accounts (account_id)
);

付款属于账户,账户属于用户。

我想选择accounts 中属于特定用户的所有行,以及子表paymentsamount 列的总和,但仅适用于extra_charge 列所在的付款0.

我开始使用子查询:

SELECT
  a.account_id,
  COALESCE(t.total_amount, 0) total_amount
FROM
  accounts a
LEFT JOIN (
  SELECT
    p.account_id,
    SUM(p.amount) total_amount
  FROM
    payments p
  WHERE
    p.extra_charge = 0
  GROUP BY
    p.account_id
) p USING (account_id)
WHERE
  a.user_id = ?;

但这运行缓慢,因为对整个 payments 表求和是很多不必要的工作。通过这样做,我可以避免不必要地对整个 payments 表求和:

SELECT
  a.account_id,
  COALESCE(t.total_amount, 0) total_amount
FROM
  accounts a
LEFT JOIN (
  SELECT
    p.account_id,
    SUM(p.amount) total_amount
  FROM
    payments p
  LEFT JOIN
    accounts a USING (account_id)
  WHERE
    a.user_id = ?
      AND
    p.extra_charge = 0
  GROUP BY
    p.account_id
) p USING (account_id)
WHERE
  a.user_id = ?;

但提供两次user_id 似乎很麻烦。

我也尝试过只使用连接而不使用子查询来编写它:

SELECT
  a.account_id
  SUM(p.amount) total_amount
FROM
  accounts a
LEFT JOIN
  payments p USING (account_id)
WHERE
  a.user_id = ?
    AND
  p.extra_charge = 0
GROUP BY
 a.account_id;

但是我的结果是缺少任何没有付款的帐户(或者没有任何付款,extra_charge = 0)。

谁能提出一个更好的方法来编写这个查询?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    使用 join 和 where 子句进行过滤

    select u.user_id ,p.account_id ,sum(p.amount) as totalAmount
    from payments p inner join accounts a
    on a.account_id=p.account_id 
    inner join users u on a.user_id=u.user_id
    where p.extra_charge =0
    group by u.user_id ,p.account_id 
    

    【讨论】:

    • 像我的第三个示例一样,此查询不会返回任何没有付款的帐户(或在extra_charge = 0 的情况下没有付款)
    • @Dave 是的,如果您使用过滤器进行限制,那么它不会返回任何帐户 ID,并且加入是最好的方法
    • @Dave 有帮助吗?
    • 我能够通过不使 WHERE 子句如此严格并缩小我的 JOIN 子句来做到这一点。我必须将其设置为以帐户作为主表的 LEFT JOIN。 stackoverflow.com/a/51791734/3438226 不过还是谢谢!
    【解决方案2】:

    我明白了:

    代替

    SELECT
      a.account_id,
      SUM(p.amount) total_amount
    FROM
      accounts a
    LEFT JOIN
      payments p USING (account_id)
    WHERE
      a.user_id = ?
       AND
     p.extra_charge = 0
    GROUP BY
      a.account_id;
    

    我用过

    SELECT
      a.account_id,
      COALESCE(SUM(p.amount), 0) total_amount
    FROM
      accounts a
    LEFT JOIN
      payments p ON p.account_id = a.account_id AND p.extra_charge = 0
    WHERE
      a.user_id = ?
    GROUP BY
      a.account_id;
    

    我扩大了 WHERE 子句但限制了 JOIN。现在我的帐户也没有有效付款。

    【讨论】:

      猜你喜欢
      • 2019-12-08
      • 2011-06-08
      • 1970-01-01
      • 2016-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      相关资源
      最近更新 更多