架构:
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)和波兰(PL)获得25和370
- CZ的费用为350,PL的费用为20
- CZ可多赚11点,PL可多赚5点
现在,我想获得以下问题的答案:
- 我们上个月在每个国家/地区有几件商品?
- 每个国家的总收入金额(付款总额。金额)是多少?
- 每个国家的总成本(商品价格总和)是多少?
- 每个国家的总额外收入(总金额的总和)是多少?
使用以下查询(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的Cost和extra_earned无效-450(而不是350)和16(而不是11)无效。PL的成本和收入也无效-它们加倍。
我了解,在LEFT OUTER JOIN
有item.id = 1的item会有2行的情况下(对于其他匹配,依此类推),但是我不知道如何构建适当的查询。
问题:
- 如何避免在多个表的查询中聚合导致错误的结果?
- 在不同值上计算和的最佳方法是什么(在这种情况下为items.id)?
PostgreSQL版本:9.6.1
选项3可以使用,但在这种情况下,它将需要
—
Stranger6667
Seq Scan
付款,这意味着将重新计算所有项目的统计信息。我没有在问题中提到这一点,但我也想按创建时间过滤项目,因此我只需要聚合数据的特定子集。我会更新的问题
您可以
—
ypercubeᵀᴹ
WHERE
在子查询中添加子句或联接。但也请使用来检查选项4 LATERAL
。
您是要加入JOIN
—
Stranger6667
payments
并items
在子查询中添加WHERE
它吗?我需要对所有选项进行基准测试:)
如果要基于限制子集
—
ypercubeᵀᴹ
items.created_at
,可以。
OUTER APPLY
和使用LATERAL
连接来执行选项4 。