スキーマ:
CREATE TABLE "items" (
"id" SERIAL NOT NULL PRIMARY KEY,
"country" VARCHAR(2) NOT NULL,
"created" TIMESTAMP WITH TIME ZONE NOT NULL,
"price" NUMERIC(11, 2) NOT NULL
);
CREATE TABLE "payments" (
"id" SERIAL NOT NULL PRIMARY KEY,
"created" TIMESTAMP WITH TIME ZONE NOT NULL,
"amount" NUMERIC(11, 2) NOT NULL,
"item_id" INTEGER NULL
);
CREATE TABLE "extras" (
"id" SERIAL NOT NULL PRIMARY KEY,
"created" TIMESTAMP WITH TIME ZONE NOT NULL,
"amount" NUMERIC(11, 2) NOT NULL,
"item_id" INTEGER NULL
);
データ:
INSERT INTO items VALUES
(1, 'CZ', '2016-11-01', 100),
(2, 'CZ', '2016-11-02', 100),
(3, 'PL', '2016-11-03', 20),
(4, 'CZ', '2016-11-04', 150)
;
INSERT INTO payments VALUES
(1, '2016-11-01', 60, 1),
(2, '2016-11-01', 60, 1),
(3, '2016-11-02', 100, 2),
(4, '2016-11-03', 25, 3),
(5, '2016-11-04', 150, 4)
;
INSERT INTO extras VALUES
(1, '2016-11-01', 5, 1),
(2, '2016-11-02', 1, 2),
(3, '2016-11-03', 2, 3),
(4, '2016-11-03', 3, 3),
(5, '2016-11-04', 5, 4)
;
だから、私たちは持っています:
- PLの1のCZの3アイテム
- CZで370、PLで25
- CZで350、PLで20
- CZで11の追加獲得、PLで5の追加獲得
今、私は以下の質問に対する答えを得たいです:
- 先月、どの国にいくつアイテムがありましたか?
- 各国で獲得した合計金額(payments.amountsの合計)は?
- 各国の合計費用(items.priceの合計)はどれくらいですか?
- 各国の追加の総収入(extras.amountの合計)はどれくらいでしたか?
次のクエリ(SQLFiddle)の場合:
SELECT
country AS "group_by",
COUNT(DISTINCT items.id) AS "item_count",
SUM(items.price) AS "cost",
SUM(payments.amount) AS "earned",
SUM(extras.amount) AS "extra_earned"
FROM items
LEFT OUTER JOIN payments ON (items.id = payments.item_id)
LEFT OUTER JOIN extras ON (items.id = extras.item_id)
GROUP BY 1;
結果は間違っています:
group_by | item_count | cost | earned | extra_earned
----------+------------+--------+--------+--------------
CZ | 3 | 450.00 | 370.00 | 16.00
PL | 1 | 40.00 | 50.00 | 5.00
CZのコストとextra_earnedは無効です-350ではなく450と11ではなく16です。PLのコストと獲得額も無効です-それらは2倍になります。
私は、LEFT OUTER JOIN
items.id = 1(他の一致の場合も同様)のアイテムの行が2行ある場合は理解しますが、適切なクエリを作成する方法がわかりません。
質問:
- 複数のテーブルでのクエリの集計で誤った結果を回避するにはどうすればよいですか?
- 個別の値(その場合はitem.id)の合計を計算する最良の方法は何ですか?
PostgreSQLバージョン:9.6.1
Seq Scan
は支払い時に必要になります。つまり、統計はすべてのアイテムで再計算されます。質問ではこれについて言及しませんでしたが、作成時間でアイテムをフィルター処理したいので、集計データの特定のサブセットのみが必要になります。質問を更新します
WHERE
サブクエリに句または結合を追加できます。ただし、オプション4もチェックしてくださいLATERAL
。
payments
とitems
サブクエリでそれを追加WHERE
することを意味しますか?すべてのオプションをベンチマークする必要があります:)
items.created_at
、はい。
OUTER APPLY
し、使用してLATERAL
代わりに参加します。