我刚刚查看了一些为8.4 之前的 PostgreSQL编写的旧代码,我看到了一些非常棒的东西。我记得以前有一个自定义函数可以做一些这样的事情,但我忘记了预先的array_agg()样子。回顾一下,现代聚合是这样写的。
SELECT array_agg(x ORDER BY x DESC) FROM foobar;
Run Code Online (Sandbox Code Playgroud)
然而,曾几何时,它是这样写的,
SELECT ARRAY(SELECT x FROM foobar ORDER BY x DESC);
Run Code Online (Sandbox Code Playgroud)
所以,我用一些测试数据试了一下..
CREATE TEMP TABLE foobar AS
SELECT * FROM generate_series(1,1e7)
AS t(x);
Run Code Online (Sandbox Code Playgroud)
结果令人惊讶..#OldSchoolCool 方式要快得多:加速了 25%。此外,在没有ORDER 的情况下简化它,表现出同样的缓慢。
# EXPLAIN ANALYZE SELECT ARRAY(SELECT x FROM foobar);
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Result (cost=104425.28..104425.29 rows=1 width=0) (actual time=1665.948..1665.949 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Seq Scan on foobar (cost=0.00..104425.28 rows=6017728 width=32) (actual time=0.032..716.793 rows=10000000 loops=1) …Run Code Online (Sandbox Code Playgroud) 我的问题的小提琴可以在https://dbfiddle.uk/?rdbms=postgres_10&fiddle=3cd9335fa07565960c1837aa65143685上找到。
我有一个简单的表格布局:
class
person: belongs to a class
Run Code Online (Sandbox Code Playgroud)
我想选择所有班级,对于每个班级,我想要按降序排列的所属人员的前两个人员标识符。
我通过以下查询解决了这个问题:
select c.identifier, array_agg(p.identifier order by p.name desc) as persons
from class as c
left join lateral (
select p.identifier, p.name
from person as p
where p.class_identifier = c.identifier
order by p.name desc
limit 2
) as p
on true
group by c.identifier
order by c.identifier
Run Code Online (Sandbox Code Playgroud)
注意:我可以在SELECT子句中使用相关子查询,但作为学习过程的一部分,我试图避免这种情况。
如您所见,我order by p.name desc在两个地方申请:
有没有办法避免这种情况?我的坚持:
首先,显然我不能删除order by子查询中的 ,因为这会给出一个不符合我上述要求的查询。
其次,我认为order by聚合函数中的 不能被遗漏,因为子查询的行顺序不一定保留在聚合函数中?
我应该重写查询吗?
我有一个关于如何JOIN在多个表上工作的基本问题。我想计算link1&中外键的出现次数link2
CREATE TABLE main (
id SERIAL PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE link1 (
id SERIAL PRIMARY KEY,
main_id integer NOT NULL,
CONSTRAINT main_id_fk FOREIGN KEY (main_id) REFERENCES main (id)
);
-- link2 is similar to link1
Run Code Online (Sandbox Code Playgroud)
当两列中的计数都不为零时,为什么下面的查询会给出计数的乘积(而不是总和)。
SELECT main.id, COUNT(link1.main_id) + COUNT(link2.main_id)
FROM main
LEFT JOIN link1 ON main.id=link1.main_id
LEFT JOIN link2 ON main.id=link2.main_id
GROUP BY main.id
Run Code Online (Sandbox Code Playgroud)