窗口函数,尝试从连接表中的列中按 created_at 排序而不分组

Posted

技术标签:

【中文标题】窗口函数,尝试从连接表中的列中按 created_at 排序而不分组【英文标题】:Window function, trying to order by created_at from a column in join table without grouping 【发布时间】:2016-02-12 15:29:25 【问题描述】:

我正在尝试为特定用户选择所有线程主题,但我想通过最近发送的消息按最新线程排序。这是我的数据库架构。

create table thread (
    id bigserial primary key,
    subject text not null,
    created timestamp with time zone not null default current_timestamp
);

create table thread_account (
    account bigint not null references account(id) on delete cascade,
    thread bigint not null references thread(id) on delete cascade
);
create index thread_account_account on thread_account(account);
create index thread_account_thread on thread_account(thread);

create table message (
    id bigserial primary key,
    thread bigint not null references thread(id) on delete cascade,
    content text not null,
    account bigint not null references account(id) on delete cascade,
    created timestamp with time zone not null default current_timestamp
);
create index message_account on message(account);
create index message_thread on message(thread);

然后我正在做一个类似的查询

select * 
FROM thread_account 
JOIN thread on thread.id = thread_account.thread
JOIN message on message.thread = thread_account.thread 
WHERE thread_account.account = 299
ORDER BY message.created desc;

但这只是为每个有消息的条目返回一个所有线程主题的列表。 (在 message.thread = thread_account.thread 上加入消息)似乎是问题所在。有人告诉我我需要一个窗口功能,但似乎无法弄清楚。顺便说一下,这是给 Postgres 的。

【问题讨论】:

我不明白你的问题,请多解释,或者写出你想要的输出 很抱歉。所以我有 5 个线程,线程只有 id、created 和 subject 列。但我想按最近发送的消息的顺序返回线程。 IE message.created 而不是 thread.created。消息通过 thread_account 加入线程。我只想按最近消息的顺序返回 5 个线程。但我目前返回 1000 个条目(整个数据库中的每条消息一个)。这有意义吗? 处理您的查询。 解释一下:IE message.created 而不是thread.created 我希望通过发送的最新消息来更新线程。消息通过 thread_account 表附加到线程 【参考方案1】:

我认为您正在寻找类似的东西:

select * 
FROM thread_account 
JOIN thread on thread.id = thread_account.thread
JOIN message on message.thread = thread_account.thread 
WHERE thread_account.account = 299
ORDER BY MAX(message.Created) OVER (PARTITION BY thread.id) desc;

小调整是 ORDER BY 中的窗口函数。这将按thread.id 对您的结果集进行分区,因此您最终会得到每个thread.id 的记录块,然后它会为每个记录块找到max(message.created)。然后它使用max(message.created) 对结果集进行排序。

窗口函数一开始有点难以理解,但只需将它们视为对记录进行分块(分区),然后将某种聚合或函数应用于该块中的一个字段,例如 @ 987654326@。


正如您在评论中提到的,您不想看到消息的信息,而只想看到线程。您只需要在查询的SELECT 部分中指定结果集中需要哪些字段。您可以使用GROUP BYDISTINCT 为每个线程获取一条记录。

此外,我们还可以将该窗口函数复制到Select 部分,从而在结果中显示最后消息日期:

SELECT DISTINCT 
    thread_account.*, 
    thread.*, 
    MAX(message.Created) OVER (PARTITION BY thread.id) as Last_Message_Date
FROM thread_account 
JOIN thread on thread.id = thread_account.thread
JOIN message on message.thread = thread_account.thread 
WHERE thread_account.account = 299
ORDER BY MAX(message.Created) OVER (PARTITION BY thread.id) desc;

如果您只想要来自ThreadThread_Account 的某些字段,那么您只需在查询的SELECT 部分中变得更加明确,例如SELECT DISTINCT Thread.Id, Thread_Account.Account, etc..

【讨论】:

所以这仍然返回我在数据库中的所有消息的所有条目。线程 1 的 IE 50 消息,线程 2 的 300 条消息。我正在寻找线程的(不是消息的消息和条目,只是按创建的消息排序)。我们越来越近了!感谢您的帮助 明白了。我为使用DISTINCTGROUP BY 的答案添加了一些额外的帮助,以及如何更明确地说明从连接表返回的字段。 哦,这太棒了!非常感谢。那解决了它。非常感谢您的帮助。 @user3858739 这个错误至少有两种方式。在采用之前仔细检查结果。 哈哈真的吗? @ClodoaldoNeto 为什么错了。它似乎正在工作【参考方案2】:

非常方便的distinct on 让事情变得简单:

select distinct on (t.id) *
from
    thread_account ta
    inner join
    thread t on t.id = ta.thread
    inner join
    message m on m.thread = ta.thread 
where ta.account = 299
order by t.id, m.created desc

只需要线程信息:

select distinct on (t.id) t.*

【讨论】:

以上是关于窗口函数,尝试从连接表中的列中按 created_at 排序而不分组的主要内容,如果未能解决你的问题,请参考以下文章

pyspark:数据框在另一个数据框的列中按ID选择行

使用 XLRD 从 excel 表中的列中读取 int 值

循环遍历一张表中的列值并将另一列中的 COUNTIF 值粘贴到另一张表中

如何从存储过程的表中的列中获取输出参数

您可以从一个表中的列中调用数据以在 SQL 和 Laravel 中的另一个表中使用吗?

什么函数允许我根据R中列中的值从数据框中的列中提取数据?