Database 如何从每个用户那里获得20个用户和5篇文章?
Database 如何从每个用户那里获得20个用户和5篇文章?,database,ruby-on-rails-3,postgresql,rdbms,Database,Ruby On Rails 3,Postgresql,Rdbms,用户可以有许多文章 我想得到20个最近的用户,每个用户有5篇文章 我一直在读,但对于我的场景来说,这似乎太复杂了。然而,文章中提到的查询速度惊人!有人告诉我。也许有一种方法可以合并查询中使用的一些方法 我使用Postgres 9.2,假设“最近”用户的意思是“最近创建的”: 虚拟数据设置 首先,生成一些虚拟数据。我没有费心把它格式化: create table users ( id serial primary key, username text not null,created_at tim
用户
可以有许多文章
我想得到20个最近的用户,每个用户有5篇文章
我一直在读,但对于我的场景来说,这似乎太复杂了。然而,文章中提到的查询速度惊人!有人告诉我。也许有一种方法可以合并查询中使用的一些方法
我使用Postgres 9.2,假设“最近”用户的意思是“最近创建的”:
虚拟数据设置
首先,生成一些虚拟数据。我没有费心把它格式化:
create table users ( id serial primary key, username text not null,created_at timestamptz not null default current_timestamp );
create table articles (id serial primary key, user_id integer not null references users(id), created_at timestamptz not null default current_timestamp);
insert into users (username) values ('todd'),('bob'),('janet'),('joan'),('jim'),('jolly'),('roger'),('yarr'),('fred');
update users set created_at = current_timestamp + id * INTERVAL '1' MINUTE;
insert into articles(user_id, created_at) select u.id, x from users u cross join generate_series(current_timestamp, current_timestamp + INTERVAL '1' HOUR, INTERVAL '1' MINUTE) x;
PostgreSQL 9.3beta1及以上版本:LATERAL
现在,这是一个遗憾的时刻,你没有在9.3上;在这里,您可以使用一个横向子查询很好地完成这一切:
SELECT u.username, a.id AS article_id
FROM (
SELECT u1.id, u1.username
FROM users u1
ORDER BY u1.created_at DESC LIMIT 5
) u,
LATERAL (
SELECT a1.id
FROM articles a1
WHERE a1.user_id = u.id
ORDER BY a1.created_at DESC LIMIT 5
) a;
见:
然而,由于9.3还没有完全发布,所以不使用它也就不足为奇了
PostgreSQL 9.2及更高版本:
在9.2及以上版本中,您必须使用另一层子查询来解决横向
支持不足的问题,您将面临一些棘手的解决方案,包括行数
窗口函数和嵌套子查询。看,
比如:
WITH
last_five_users AS (
SELECT u1.id, u1.username FROM users u1 ORDER BY u1.created_at DESC LIMIT 5
)
SELECT
lfa.username, lfa.article_id
FROM
(
SELECT lfive.username, lfive.id, a.id, row_number() OVER (PARTITION BY a.user_id ORDER BY created_at)
FROM articles a
INNER JOIN last_five_users lfive ON (a.user_id = lfive.id)
) AS lfa(username, user_id, article_id, rownum)
WHERE lfa.rownum <= 10;
然后在主查询中使用该选项:
SELECT
o.username,
(o.last_articles).*
FROM (
SELECT
u.username,
last_n_articles_for_user(u.id, 10) AS last_articles
FROM (
SELECT *
FROM users u1
ORDER BY u1.created_at DESC
LIMIT 5
) u
) AS o;
如果在中创建了
索引,这可能会表现得更好,尽管不如9.3中启用的横向
方法。需要额外的子查询层,因为直接使用*
语法为用户调用last\u n\u articles\u将导致每个列调用一次子查询(由于PostgreSQL对行返回函数的内部限制)。您确实应该尝试提供一些示例数据和预期结果,省去了需要装假的麻烦+1无论如何,为了一个半体面的解释和提及你的版本。定义“最近的用户”。最近创建的?最近活跃?最近发表了一篇文章?非常好的解释和示例的使用+1横向功能看起来确实很有趣,感谢您提到集合函数方法
SELECT
o.username,
(o.last_articles).*
FROM (
SELECT
u.username,
last_n_articles_for_user(u.id, 10) AS last_articles
FROM (
SELECT *
FROM users u1
ORDER BY u1.created_at DESC
LIMIT 5
) u
) AS o;