首页 > 编程问答 >按时间顺序将表 A 中的每条信息与表 B 中的最早回复列出

按时间顺序将表 A 中的每条信息与表 B 中的最早回复列出

时间:2024-05-31 22:05:46浏览次数:20  
标签:sql postgresql join

我有三个表: conversations , user_messages system_messages .它们的基本结构(为简洁起见删除了无关列)是:

创建表 conversations(默认生成 id int 作为身份主键);

创建表 user_messages(
   创建表 user_messages(
  ,conversation_id int 引用 conversations(id)
  内容文本
  创建时间);

创建表 system_messages(
   默认情况下作为标识主键生成的 int
  ,conversation_id int 引用 conversations(id)
  内容文本
  创建时间);

我正试图为给定的对话生成 "system said X" 和 "user responded with Y" 行的导出。我遇到的问题是如何确保 "user responded with Y" 消息与对话中按时间顺序排列的下一条消息相对应,紧随系统消息之后。因此,输出结果将如下所示:

more
system_said system_said user_said
你好! 你好 你好! 你好! 你好 你好 你好吗? 我很好,你呢? 你好吗? 你好吗? 我很好! 很好。 不错。

    This works , but with a poor and inefficient query, using a sub-query that references outer values.

    这可以工作 ,但使用一个引用外层值的子查询,效率很低。

    SELECT
        content AS system_said,(
            SELECT content
            FROM user_messages
            where conversation_id = sm.conversation_id AND created_at > sm.created_at
            ORDER BY created_at
            LIMIT 1
        )AS user_said
    FROM system_messages sm
    WHERE sm.conversation_id = ?
    

  1. 这就是我卡住的地方。我正试图使用适当的连接更有效地重写上述内容,但我无法强制连接给我按时间顺序排列的下一条消息,因此我得到了以下混淆的对子:

    system_said system_said user_said
    你好! 不错。 你好吗? 你好吗? 你好 你好。 你好吗? 我很好! 我很好,你呢?

    下面是查询:

    SELECT
        DISTINCT ON (sm) sm.id AS message、
        sm.content AS system_said、
        um.content AS user_said
    FROM system_messages sm
    连接
        SELECT conversation_id、created_at、content
        FROM user_messages
        ORDER BY created_at
    ) um ON um.conversation_id = sm.conversation_id AND um.created_at > sm.created_at
    ORDER BY sm
    WHERE c.id = ?
    

    (我发现必须添加 DISTINCT ON () 否则会出现重复行。

有办法解决这个问题吗?


可以使用窗口函数来实现这一点,特别是在这种情况下是 LEAD() 函数。 LEAD() 函数允许窥视分区中的下一行,这对于获取系统消息之后的下一条用户消息是完美的。

以下是如何修改的查询以获得所需结果的方法:

WITH TimeOrderedMessages AS (
    SELECT
        sm.content AS system_said,
        um.content AS user_said,
        LEAD(um.content, 1) OVER (PARTITION BY sm.conversation_id ORDER BY um.created_at) AS next_user_said,
        um.created_at AS user_created_at
    FROM
        system_messages sm
    LEFT JOIN
        user_messages um ON sm.conversation_id = um.conversation_id AND um.created_at > sm.created_at
    WHERE 
        sm.conversation_id = ?
)
SELECT 
    system_said, 
    user_said
FROM 
    TimeOrderedMessages
WHERE 
    user_created_at = (SELECT MIN(user_created_at) FROM TimeOrderedMessages WHERE system_said = TimeOrderedMessages.system_said)
ORDER BY 
    user_created_at;

说明:

  1. CTE(公用表表达式): 查询首先使用 WITH 子句创建一个名为 TimeOrderedMessages 的 CTE。这有助于使查询更具可读性和组织性。
  2. LEAD(um.content, 1) OVER (PARTITION BY sm.conversation_id ORDER BY um.created_at) 这部分是关键。它使用 LEAD() 函数在 user_messages 表的上下文中获取按 created_at 排序的每个系统消息的 next user_said 值,这些值由 conversation_id 分组。
  3. LEFT JOIN: 我们使用 LEFT JOIN 来包含没有相应用户消息的系统消息。如果只需要成对的消息,则可以使用 INNER JOIN
  4. WHERE 子句: CTE 中的 WHERE 子句过滤结果以仅包含与提供的 conversation_id 匹配的消息。
  5. 外部选择和排序: 然后,外部查询选择 system_said user_said 列。 ORDER BY um.created_at 子句确保按时间顺序呈现响应。

此查询避免了之前方法中的子查询,从而使其更加高效。它利用窗口函数来查找按时间顺序排列的下一条用户消息,为提供所需的确切对话流。

标签:sql,postgresql,join
From: 78559954

相关文章

  • PHP执行sql
    PHP连接MySQL连接数据库<?php$severname='localhost';$username='root';$password='123456';$dbanme='数据库名'//创建连接$conn=newmysqli($servername,$username,$password,$dbname);//连接检测if($conn->connect_error){......
  • 成为MySQL DBA后,再看ORACLE数据库(四、系统视图)
    在数据库的运维管理中,熟悉数据库系统视图的使用可以帮助我们了解数据库各方面的状态信息。一般数据库的系统视图分为数据字典视图和动态性能视图,数据字典视图用于显示数据库的元数据信息和系统状态信息包括各种数据库对象、用户、角色、权限等;动态性能视图用于显示数据库的性能统......
  • MySQL基础索引知识【索引创建删除 | MyISAM & InnoDB引擎原理认识】
      博客主页:花果山~程序猿-CSDN博客文章分栏:MySQL之旅_花果山~程序猿的博客-CSDN博客关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!目录 一,索引用处二,磁盘三,mysql与磁盘的基本交互单位四,管理page的数据结构(InnoDB引擎下)单个page多个pa......
  • PHP执行sql
    PHP连接MySQL连接数据库<?php$severname='localhost';$username='root';$password='123456';$dbanme='数据库名'//创建连接$conn=newmysqli($servername,$username,$password,$dbname);//连接检测if($conn->connect_error){......
  • MyBatis实战:如何将拼接的SQL打印到日志
    哈喽,大家好,我是木头左!一、前言在日常开发中,经常会遇到拼接SQL的情况,这时候,如何将拼接的SQL打印到日志,以便追踪和调试呢?本文将详细介绍MyBatis如何实现这一功能。二、MyBatis简介MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有......
  • 免费、开源、好用的 SQL 客户端合集
    0、SQLChatSQLChat是2023年3月推出的新型SQL客户端,它将数据库管理带入了基于聊天的新时代。SQLChat由ChatGPT驱动,能够帮你编写和润色SQL语句,让数据库操作变得更加智能和便捷。目前支持MySQL、PostgreSQL和MSSQL数据库。官方地址:https://www.sqlchat.ai......
  • 【SQL DB - 关系型数据库是如何工作的】
    SQLDB-关系型数据库是如何工作的从数据结构说起时间复杂度归并排序二叉搜索树B+树索引哈希表全局概览核心组件工具查询管理器数据管理器:数据查询的流程客户端管理器查询管理器查询解析器查询重写器统计查询优化器索引存取路径联接运算符嵌套循环联接哈希联接合并联接......
  • MYSQL数据库
    创建数据库createdatabasemyDB;删除数据库dropdatabasefirstDB;选择数据库usemyDB;创建表mysql>createtablePEOPLE(->IDintAUTO_INCREMENTPRIMARYKEY,->NAMEvarchar(20)notnull,->PASSWORDtinyint(50)notnull,->AGEintno......
  • sqlSugar 使用原生模式链接数据库
    usingSystem.Reflection;usingzhulongxu_webapi_pro.Tools;namespacezhulongxu_webapi_pro.Services{///<summary>///初始化数据库///</summary>publicstaticclassInitDataBaseService{publicstaticvoidInitDataBase......
  • mysql查询表基础信息
    --一、查询数据库名称为db_name的所有表 SELECTt.table_catalog,t.table_schema,t.table_name,table_typeFROMinformation_schema.TABLEStwheret.table_schema='db_name'SELECTt.table_catalog,t.table_schema,t.table_name,table_typeFROMinformation_schema.TABLES......