web-dev-qa-db-ja.com

異なるテーブルから列の合計を引く方法は?

2つのテーブルがあります。

  1. 引き出し:account_id + amount
  2. 賞品:account_id + amount

おそらくaccountで、VIEWごとの残高を計算したいと思います。

私は2つのクエリを持つことができます:

SELECT account_id, SUM(amount) FROM prizes GROUP BY account_id

これにより、アカウントごとの合計賞金が得られます。

SELECT account_id, SUM(amount) FROM withdrawals GROUP BY account_id

これにより、これらのアカウントのすべての引き出しが可能になります。

今、私は私の口座の残高を返すためにそれらを差し引きたいと思います。そのようなビューを作成する最も効率的な方法は何ですか?

2
Kamil Lelonek

グループ化された結果を完全に結合し、合計の差を構築できます。

CREATE VIEW balance
AS
SELECT coalesce(x.account_id, y.account_id) account_id,
       coalesce(x.amount, 0) - coalesce(y.amount, 0) amount
       FROM (SELECT account_id,
                    sum(amount) amount
                    FROM prizes
                    GROUP BY account_id) x
            FULL JOIN (SELECT account_id,
                              sum(amount) amount
                              FROM withdrawals
                              GROUP BY account_id) y
                      ON x.account_id = y.account_id;

編集:

賞金や引き出しのないアカウントの残高も0にする場合は、サブクエリをアカウントに残しておきます。

CREATE VIEW balance
            SELECT a.id account_id,
                   coalesce(x.amount, 0) - coalesce(y.amount, 0) amount
                   FROM accounts a
                        LEFT JOIN (SELECT account_id,
                                          sum(amount) amount
                                          FROM prizes
                                          GROUP BY account_id) x
                                  ON x.account_id = a.id
                        LEFT JOIN (SELECT account_id,
                                          sum(amount) amount
                                          FROM withdrawals
                                          GROUP BY account_id) y
                                  ON y.account_id = a.id;
2
sticky bit

完全結合の代わりに、UNION ALLを使用して2つの集約されたセットを組み合わせることができます。否定された結果にはwithdrawalsセットのみが含まれます。次に、組み合わせたセットを派生テーブルとして使用し、account_idごとの金額をもう一度集計します。

SELECT
  account_id,
  SUM(amount) AS balance
FROM
  (
    SELECT
      account_id,
      SUM(amount) AS amount
    FROM
      prizes
    GROUP BY
      account_id

    UNION ALL

    SELECT
      account_id,
      -SUM(amount) AS amount
    FROM
      withdrawals
    GROUP BY
      account_id
  ) AS derived
GROUP BY
  account_id
;

このクエリが完全な結合ソリューションとどのように比較されるかはわかりませんが、良い出発点として適格であるように私には十分に単純に見えます。

5
Andriy M