Tan*_*aki 5 sql postgresql join aggregate-functions left-join
我试图在单个SQL查询中使用多个表的多个聚合函数(使用Postgres).
我的表结构类似于以下内容:
CREATE TABLE user (user_id INT PRIMARY KEY, user_date_created TIMESTAMP NOT NULL);
CREATE TABLE item_sold (item_sold_id INT PRIMARY KEY, sold_user_id INT NOT NULL);
CREATE TABLE item_bought (item_bought_id INT PRIMARY KEY, bought_user_id INT NOT NULL);
Run Code Online (Sandbox Code Playgroud)
我想计算每个用户购买和销售的商品数量.我想到的解决方案不起作用:
SELECT user_id, COUNT(item_sold_id), COUNT(item_bought_id)
FROM user
LEFT JOIN item_sold ON sold_user_id=user_id
LEFT JOIN item_bought ON bought_user_id=user_id
WHERE user_date_created > '2014-01-01'
GROUP BY user_id;
Run Code Online (Sandbox Code Playgroud)
这似乎执行了(item_sold_id,item_bought_id)的所有组合,例如,如果有4个已售出且2个已购买,则两个COUNT()都是8.
如何正确查询表以获取两个计数?
您查询的简单方法是使用distinct
:
SELECT user_id, COUNT(distinct item_sold_id), COUNT(distinct item_bought_id)
FROM user
LEFT JOIN item_sold ON sold_user_id=user_id
LEFT JOIN item_bought ON bought_user_id=user_id
WHERE user_date_created > '2014-01-01'
GROUP BY user_id;
Run Code Online (Sandbox Code Playgroud)
但是,查询正在进行不必要的工作.如果有人购买了100件商品并销售了200件商品,那么该连接将产生20,000个中间行.那是很多.
解决方案是预先聚合结果或使用相关的子查询select
.在这种情况下,我更喜欢相关子查询解决方案(假设正确的索引可用):
SELECT u.user_id,
(select count(*) from item_sold s where u.user_id = s.sold_user_id),
(select count(*) from item_bought b where u.user_id = b.bought_user_id)
FROM user u
WHERE u.user_date_created > '2014-01-01';
Run Code Online (Sandbox Code Playgroud)
正确的索引是item_sold(sold_user_id)
和item_bought(bought_user_id)
.由于对user
表的过滤,我更喜欢这种预聚合.这仅对今年创建的用户进行了计算 - 这对于预聚合来说更难.