Sql 获取最新的子消息以及无子消息的父消息
下面是消息模型Sql 获取最新的子消息以及无子消息的父消息,sql,ruby-on-rails,postgresql,activerecord,greatest-n-per-group,Sql,Ruby On Rails,Postgresql,Activerecord,Greatest N Per Group,下面是消息模型 class Message < ApplicationRecord belongs_to :parent_message, class_name: 'Message', optional: true has_many :child_messages, foreign_key: :parent_message_id, class_name: "Message" has_many :message_participants scope :latest_mess
class Message < ApplicationRecord
belongs_to :parent_message, class_name: 'Message', optional: true
has_many :child_messages, foreign_key: :parent_message_id, class_name: "Message"
has_many :message_participants
scope :latest_messages_by_participant, -> (user_id) do
select("DISTINCT ON (parent_message_id) messages.*").
joins(:message_participants).
where(message_participants: { user_id: user_id }).
order("parent_message_id, created_at DESC")
end
end
类消息(用户id)do
选择(“在(父消息\u id)消息上不同。*”)。
加入(:消息\参与者)。
其中(消息参与者:{user\u id:user\u id})。
订单(“父消息id,在描述处创建”)
结束
结束
消息\u参与者
对每条消息以及发送或接收该消息的不同人员都有记录。它上面有一个用户id
上述参与者提供的最新消息\u的问题在于,它能够获取所有子消息,但只获取最后一条父消息。这是因为我们在parent_message_id上调用distict,对于无子女的父消息,该值为NULL,因此它只在NULL上调用distinct,并返回1值(最后一个无子女的父消息)
如何在单个查询中获取所有最新消息,包括最新的子消息和最新的无子父消息
我使用的是Rails 6和Postgres 11
p.S:我还应该指出第二个问题,即消息是在ASC的created_中返回的。DESC处创建的_能够获取最新的子消息,但不能对整个集合进行排序。我可以通过调用.reverse来解决这个问题,但我想知道是否有办法解决这个问题。我认为您需要在您的不同的on&order by中添加一个coalese,以便在父消息\u id
为空时选择消息的id
select("DISTINCT ON (parent_message_id) messages.*")
...
order("parent_message_id, created_at DESC")
需要转化为
select("DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*")
...
order("COALESCE(parent_message_id, messages.id), created_at DESC")
现在,您还没有提供示例数据库表&预期的或完整的模型定义,因此我推断了很多事情。以下是最小的表定义(据我所知),在我建议的修改后AR将生成的原始sql查询[这是我们想要的查询,给出下面的模式]&结果
安装程序
提供最后一条父消息或子消息的原始SQL查询:
结果
给定user\u id=1
,上述查询将返回结果:
id | parent_message_id | created_at
----+-------------------+----------------------------
1 | | 2020-05-11 13:50:00.857589
4 | | 2020-05-11 13:50:00.857589
(2 rows)
id | parent_message_id | created_at
----+-------------------+----------------------------
2 | 1 | 2020-05-11 13:50:00.857589
5 | | 2020-05-11 13:52:01.261975
(2 rows)
给定user\u id=2
,上述查询将返回结果:
id | parent_message_id | created_at
----+-------------------+----------------------------
1 | | 2020-05-11 13:50:00.857589
4 | | 2020-05-11 13:50:00.857589
(2 rows)
id | parent_message_id | created_at
----+-------------------+----------------------------
2 | 1 | 2020-05-11 13:50:00.857589
5 | | 2020-05-11 13:52:01.261975
(2 rows)
对总体结果进行排序:
DESC处创建的_能够获取最新的子消息,但不能对整个集合进行排序。我可以通过打电话来解决这个问题。相反,我想知道是否有办法解决这个问题
要在数据库中进行排序,可以将上述查询包装在cte中
例如:
WITH last_messages AS (
SELECT DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*
FROM messages
JOIN message_participants ON message_participants.message_id = messages.id
WHERE message_participants.user_id = 2
ORDER BY COALESCE(parent_message_id, messages.id), created_at DESC
)
SELECT * FROM last_messages ORDER BY created_at;
但是,我不能100%确定这在AR中是如何表达的,我认为您需要在不同的on&order by中添加一个coalese,以便在父消息\u id
为空时选择消息的id
select("DISTINCT ON (parent_message_id) messages.*")
...
order("parent_message_id, created_at DESC")
需要转化为
select("DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*")
...
order("COALESCE(parent_message_id, messages.id), created_at DESC")
现在,您还没有提供示例数据库表&预期的或完整的模型定义,因此我推断了很多事情。以下是最小的表定义(据我所知),在我建议的修改后AR将生成的原始sql查询[这是我们想要的查询,给出下面的模式]&结果
安装程序
提供最后一条父消息或子消息的原始SQL查询:
结果
给定user\u id=1
,上述查询将返回结果:
id | parent_message_id | created_at
----+-------------------+----------------------------
1 | | 2020-05-11 13:50:00.857589
4 | | 2020-05-11 13:50:00.857589
(2 rows)
id | parent_message_id | created_at
----+-------------------+----------------------------
2 | 1 | 2020-05-11 13:50:00.857589
5 | | 2020-05-11 13:52:01.261975
(2 rows)
给定user\u id=2
,上述查询将返回结果:
id | parent_message_id | created_at
----+-------------------+----------------------------
1 | | 2020-05-11 13:50:00.857589
4 | | 2020-05-11 13:50:00.857589
(2 rows)
id | parent_message_id | created_at
----+-------------------+----------------------------
2 | 1 | 2020-05-11 13:50:00.857589
5 | | 2020-05-11 13:52:01.261975
(2 rows)
对总体结果进行排序:
DESC处创建的_能够获取最新的子消息,但不能对整个集合进行排序。我可以通过打电话来解决这个问题。相反,我想知道是否有办法解决这个问题
要在数据库中进行排序,可以将上述查询包装在cte中
例如:
WITH last_messages AS (
SELECT DISTINCT ON (COALESCE(parent_message_id, messages.id)) messages.*
FROM messages
JOIN message_participants ON message_participants.message_id = messages.id
WHERE message_participants.user_id = 2
ORDER BY COALESCE(parent_message_id, messages.id), created_at DESC
)
SELECT * FROM last_messages ORDER BY created_at;
但是,我不能100%确定这将如何在AR中表达在中使用合并
表达式,在上使用不同的
和顺序
并在外部查询中对结果进行排序,以获得所需的排序顺序:
SELECT *
FROM (
SELECT DISTINCT ON (COALESCE(m.parent_message_id, m.id))
m.*
FROM messages m
JOIN message_participants mp ON ...
WHERE mp.user_id = ...
ORDER BY (COALESCE(m.parent_message_id, m.id)), created_at DESC
)
ORDER BY created_at;
见(附详细说明):
演出
对于每个用户和消息ID的少数行,
上的DISTINCT通常是最快的解决方案之一。对于许多行,有(更多)更快的方法。取决于更多信息,如注释所示。在中使用合并
表达式,在
和排序依据
并在外部查询中对结果进行排序,以获得所需的排序顺序:
SELECT *
FROM (
SELECT DISTINCT ON (COALESCE(m.parent_message_id, m.id))
m.*
FROM messages m
JOIN message_participants mp ON ...
WHERE mp.user_id = ...
ORDER BY (COALESCE(m.parent_message_id, m.id)), created_at DESC
)
ORDER BY created_at;
见(附详细说明):
演出
对于每个用户和消息ID的少数行,
上的DISTINCT通常是最快的解决方案之一。对于许多行,有(更多)更快的方法。取决于更多信息,如注释所示。实际表定义(CREATE table
语句)和一些示例数据将是有用的。一个简单的SQL语句也会有帮助。如果你关心性能,我们需要更多的信息。考虑这里的说明:最重要的是:在avg上每个用户和消息id大约有多少行?谢谢@ErwinBrandstetter,现在,性能不是一个考虑因素,但在情况发生变化时肯定会进行评估。实际的表定义(CREATE table
语句)和一些示例数据将非常有用。一个简单的SQL语句也会有帮助。如果你关心性能,我们需要更多的信息。考虑这里的说明:最重要的是:avg上每个用户和消息id大约有多少行?谢谢@ErwinBrandstetter,现在,性能不是一个考虑因素,但当情况发生变化时,肯定会进行评估。