【问题标题】:Need Help in Oracle/Postgresql Query在 Oracle/Postgresql 查询中需要帮助
【发布时间】:2014-12-06 09:47:50
【问题描述】:

这是一个要求,希望你能帮助我。

要求:

我需要获取发送者和接收者之间的最后一次对话,反之亦然。

详细来说,我在表格中有以下数据。

    sen | rec |            day             |  msg  
    -----+-----+----------------------------+-------
    A   | B   | 2014-12-05 11:51:38.213723 | HI
    B   | A   | 2014-12-05 11:51:54.486329 | HELLO
    A   | B   | 2014-12-05 11:52:10.289694 | HwRU
    B   | A   | 2014-12-05 11:52:21.613091 | FINE
    A   | C   | 2014-12-05 11:52:32.608677 | HI
    C   | A   | 2014-12-05 11:53:00.695742 | HELLO
    C   | D   | 2014-12-05 11:53:10.058141 | HELLO
    E   | D   | 2014-12-05 11:53:17.473893 | HELLO
    D   | E   | 2014-12-05 11:53:53.675839 | HI

注意:对话不分发送者和接收者。

所以,A 到 B 之间的最后一次对话是

    B   | A   | 2014-12-05 11:52:21.613091 | FINE

A 和 C 之间的最后一次对话是

    C   | A   | 2014-12-05 11:53:00.695742 | HELLO

这样,无论发送者和接收者,我都需要两个人之间的最后一次对话。

请帮帮我。

【问题讨论】:

    标签: sql postgresql oracle10g greatest-n-per-group


    【解决方案1】:

    要在不考虑排序的情况下评估(sen,rec) 组合,您可以使用least(sen,rec), greatest(sen,rec) 这可用于对数据进行分组,然后使用窗口函数使用最新的行:

    select sen, rec, day, msg
    from (
      select sen, rec, day, msg,
             row_number() over (partition by least(sen,rec), greatest(sen,rec) order by day desc) as rn
      from conversations
    ) t
    where rn = 1;
    

    【讨论】:

      【解决方案2】:
      CREATE TABLE sendrecv(
          sen CHAR(1) NOT NULL
          , rec CHAR(1) NOT NULL
          , zday TIMESTAMP NOT NULL
          , msg varchar
            , PRIMARY KEY(sen,rec,zday)  -- this will cause an index to be created
            , UNIQUE(rec, sen,zday)      -- this will create the "swapped" index
              );
      
          INSERT INTO sendrecv(sen , rec , zday, msg) values
          ('A', 'B', '2014-12-05 11:51:38.213723', 'HI' )
          ,('B', 'A', '2014-12-05 11:51:54.486329', 'HELLO' )
          ,('A', 'B', '2014-12-05 11:52:10.289694', 'HwRU' )
          ,('B', 'A', '2014-12-05 11:52:21.613091', 'FINE' )
          ,('A', 'C', '2014-12-05 11:52:32.608677', 'HI' )
          ,('C', 'A', '2014-12-05 11:53:00.695742', 'HELLO' )
          ,('C', 'D', '2014-12-05 11:53:10.058141', 'HELLO' )
          ,('E', 'D', '2014-12-05 11:53:17.473893', 'HELLO' )
          ,('D', 'E', '2014-12-05 11:53:53.675839', 'HI' )
              ;
      

      SELECT * FROM sendrecv sr
      WHERE NOT EXISTS (
              SELECT * FROM sendrecv nx
              WHERE nx.sen = sr.sen AND nx.rec = sr.rec
              AND nx.zday > sr.zday
              )
      AND NOT EXISTS (
              SELECT * FROM sendrecv nx
              WHERE nx.sen = sr.rec AND nx.rec = sr.sen
              AND nx.zday > sr.zday
              )
              ;
      

      CREATE TABLE
      INSERT 0 9
       sen | rec |            zday            |  msg  
      -----+-----+----------------------------+-------
       B   | A   | 2014-12-05 11:52:21.613091 | FINE
       C   | A   | 2014-12-05 11:53:00.695742 | HELLO
       C   | D   | 2014-12-05 11:53:10.058141 | HELLO
       D   | E   | 2014-12-05 11:53:53.675839 | HI
      (4 rows)
      

      【讨论】:

        【解决方案3】:

        如果你想找到特定两个人之间的最后一次对话(例如'A'和'B'),解决方案很简单:

        SELECT *
        FROM conversations
        WHERE 'A' IN (sen, rec) AND 'B' IN (sen, rec)
        ORDER BY "day" DESC
        LIMIT 1;
        

        为了找到任何两方之间的最后一次对话,之前发布的两个解决方案都可以使用,但我再给你一个建议:

        SELECT DISTINCT ON (LEAST(sen, rec), GREATEST(sen, rec)) *
        FROM conversations
        ORDER BY LEAST(sen, rec), GREATEST(sen, rec), "day" DESC;
        

        以上语句是为 PostgreSQL 编写的。

        【讨论】:

        • distinct on 将比在 Postgres 中使用窗口函数的解决方案更有效,但在 Oracle 中不起作用(LIMIT 1 也不会)解决方案
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-05
        • 1970-01-01
        • 2019-10-11
        • 1970-01-01
        • 1970-01-01
        • 2013-10-28
        • 1970-01-01
        相关资源
        最近更新 更多