【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
顾名思义,我想选择以GROUP BY
分组的每组行的第一行。
具体来说,如果我有一个如下的purchases
表:
SELECT * FROM purchases;
我的输出:
id | customer | total ---+----------+------ 1 | Joe | 5 2 | Sally | 3 3 | Joe | 2 4 | Sally | 1
我想查询每个customer
购买的最大商品的id
( total
)。 像这样:
SELECT FIRST(id), customer, FIRST(total)
FROM purchases
GROUP BY customer
ORDER BY total DESC;
预期产量:
FIRST(id) | customer | FIRST(total) ----------+----------+------------- 1 | Joe | 5 2 | Sally | 3
#1楼
由于存在SubQ,该解决方案不是十分有效,正如Erwin指出的那样
select * from purchases p1 where total in
(select max(total) from purchases where p1.customer=customer) order by total desc;
#2楼
这是常见的每组最多n个问题,该问题已经过测试和高度优化 。 就我个人而言,我更喜欢Bill Karwin的左联接解决方案 ( 带有许多其他解决方案的原始帖子 )。
注意,在大多数官方资料之一MySQL手册中 ,可以惊奇地找到许多针对这个常见问题的解决方案! 请参阅常见查询的示例::持有特定列的按组最大值的行 。
#3楼
快速解决方案
SELECT a.*
FROM
purchases a
JOIN (
SELECT customer, min( id ) as id
FROM purchases
GROUP BY customer
) b USING ( id );
如果用ID索引表,这真的非常快:
create index purchases_id on purchases (id);
#4楼
在Postgres中,您可以像这样使用array_agg
:
SELECT customer,
(array_agg(id ORDER BY total DESC))[1],
max(total)
FROM purchases
GROUP BY customer
这将为您提供每个客户最大购买量的id
。
注意事项:
-
array_agg
是一个聚合函数,因此可以与GROUP BY
。 -
array_agg
允许您指定array_agg
于自身的排序,因此它不会限制整个查询的结构。 如果需要执行一些与默认值不同的操作,则还提供了有关如何对NULL进行排序的语法。 - 构建数组后,我们将获取第一个元素。 (Postgres数组是1索引的,而不是0索引的)。
- 您可以以类似的方式将
array_agg
用于第三输出列,但max(total)
更简单。 - 与
DISTINCT ON
不同,使用array_agg
可使您保留GROUP BY
,以防其他原因。
#5楼
我使用这种方式(仅适用于postgresql): https : //wiki.postgresql.org/wiki/First/last_%28aggregate%29
-- Create a function that always returns the first non-NULL item
CREATE OR REPLACE FUNCTION public.first_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $1;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.first (
sfunc = public.first_agg,
basetype = anyelement,
stype = anyelement
);
-- Create a function that always returns the last non-NULL item
CREATE OR REPLACE FUNCTION public.last_agg ( anyelement, anyelement )
RETURNS anyelement LANGUAGE sql IMMUTABLE STRICT AS $$
SELECT $2;
$$;
-- And then wrap an aggregate around it
CREATE AGGREGATE public.last (
sfunc = public.last_agg,
basetype = anyelement,
stype = anyelement
);
然后您的示例应该几乎可以按以下方式工作:
SELECT FIRST(id), customer, FIRST(total)
FROM purchases
GROUP BY customer
ORDER BY FIRST(total) DESC;
CAVEAT:忽略NULL行
编辑1-改用postgres扩展名
现在,我使用这种方式: http : //pgxn.org/dist/first_last_agg/
要在ubuntu 14.04上安装:
apt-get install postgresql-server-dev-9.3 git build-essential -y
git clone git://github.com/wulczer/first_last_agg.git
cd first_last_app
make && sudo make install
psql -c 'create extension first_last_agg'
这是一个postgres扩展,为您提供第一个和最后一个功能; 显然比上述方法快。
编辑2-排序和过滤
如果使用聚合函数(如此类),则可以对结果进行排序,而无需对数据进行排序:
http://www.postgresql.org/docs/current/static/sql-expressions.html#SYNTAX-AGGREGATES
因此,带有排序的等效示例如下所示:
SELECT first(id order by id), customer, first(total order by id)
FROM purchases
GROUP BY customer
ORDER BY first(total);
当然,您可以按自己认为合适的顺序进行排序和过滤。 这是非常强大的语法。
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3141453