如何解决基于连接表的“BETWEEN”条件动态计数的 SQL 选择
我想向我的宠物项目添加一个 Messenger,但我在编写数据库查询时遇到了困难。我将 MySQL 用于此服务,并将 Hibernate 作为 ORM。几乎所有查询都是用 HQL 编写的,但原则上我可以使用原生查询。
Messenger 可以包含群组对话。除了写消息外,用户还可以进入对话、离开对话、清除个人消息历史记录。用户可以在对话中看到所有消息,但他也可以清除历史记录,只看到最后一次清除后的消息。
下面我描述了对这个任务很重要的两个表的简化结构。
消息表:
ID | 文字 | 时间戳 |
---|---|---|
1 | first_msg | 1609459200 |
2 | second_msg | 1609545600 |
Member_event 表:
id | user_id | 类型 | 时间戳 |
---|---|---|---|
1 | 1 | 1 | 1609459100 |
2 | 1 | 3 | 1609459300 |
3 | 1 | 2 | 1609459400 |
4 | 1 | 1 | 1609545500 |
where type:
1 - user entered the chat,2 - user leaved the chat,3 - user cleared his own history of messages in the chat
是否可以通过一个请求读取用户可用的所有聊天消息?
我不知道如何动态检查条件:WHERE 消息的时间戳在所有“进入-离开”周期之间以及最后一次“进入”之后(如果没有离开,但仅在最后一次历史清除之后)。如果存在。
解决方法
我认为您可以继续执行以下步骤:
- 取两个表的并集并按时间戳顺序考虑记录
- 使用窗口函数确定最近的 1 或 2 类型是否为 1。我们可以使用运行总和,其中类型 1 加一,类型 2 减一(而 3 对它没有任何作用)。使用另一个窗口函数,您可以确定是否还有类型 3 跟随。当该行属于必须收集的区间时,这两个信息的组合可以转换为 1,否则为 0。
- 过滤之前的结果只得到消息记录,只得到那些计算为 1 的记录。
这是查询:
with unified as (
select id,text,timestamp,null as type
from message
union
select id,null,type
from member_event
where user_id = 1),validated as (
select unified.*,sum(case type when 1 then 1 when 2 then -1 else 0 end)
over (order by timestamp
rows unbounded preceding) *
min(case type when 3 then 0 else 1 end)
over (order by timestamp
rows between current row and unbounded following) valid
from unified
order by timestamp)
select id,timestamp
from validated
where type is null and valid = 1
order by timestamp
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。