假设数据库中有一个表comments.

注释表有idtextshowcomment_id_no列.

如果用户输入注释,它会在数据库中插入一行

| id |  comment_id_no | text | show | inserted_at |
| -- | -------------- | ---- | ---- | ----------- |
| 1  | 1              | hi   | true | 1/1/2000    |

如果用户想要更新该注释,它会在数据库中插入一个新行

| id |  comment_id_no | text | show | inserted_at |
| -- | -------------- | ---- | ---- | ----------- |
| 1  | 1              | hi   | true | 1/1/2000    |
| 2  | 1              | hey  | true | 1/1/2001    |

注意它保持不变的comment_id_no.这样我们就能看到 comments 的历史了.

现在用户决定不再显示他们的 comments

| id |  comment_id_no | text | show  | inserted_at |
| -- | -------------- | ---- | ----- | ----------- |
| 1  | 1              | hi   | true  | 1/1/2000    |
| 2  | 1              | hey  | true  | 1/1/2001    |
| 3  | 1              | hey  | false | 1/1/2002    |

这会对最终用户隐藏 comments .

现在发表第二条 comments (不是第一条的更新)

| id |  comment_id_no | text | show  | inserted_at |
| -- | -------------- | ---- | ----- | ----------- |
| 1  | 1              | hi   | true  | 1/1/2000    |
| 2  | 1              | hey  | true  | 1/1/2001    |
| 3  | 1              | hey  | false | 1/1/2002    |
| 4  | 2              | new  | true  | 1/1/2003    |

我希望能够 Select unique commend_id_no的所有最新版本,其中show等于true.但是,我不希望查询返回id=2.

查询需要采取的步骤...

  1. Select 所有最近的、不同的comment_id_no个.(应返回id=3id=4)
  2. Select show=true的位置(应仅返回id=4)

注意:我实际上是在用elixir编写这个查询,使用的是ecto,我希望不使用子查询函数也能做到这一点.如果有人能用sql回答这个问题,我可以自己转换答案.如果有人知道如何用长生不老药来回答这个问题,那么也可以随意回答.

推荐答案

不需要使用子查询就可以使用LEFT JOIN:

SELECT  c.id, c.comment_id_no, c.text, c.show, c.inserted_at
FROM    Comments AS c
        LEFT JOIN Comments AS c2
            ON c2.comment_id_no = c.comment_id_no
            AND c2.inserted_at > c.inserted_at
WHERE   c2.id IS NULL
AND     c.show = 'true';

我认为所有其他方法都需要某种子查询,这通常需要一个排名函数:

SELECT  c.id, c.comment_id_no, c.text, c.show, c.inserted_at
FROM    (   SELECT  c.id, 
                    c.comment_id_no, 
                    c.text, 
                    c.show, 
                    c.inserted_at,
                    ROW_NUMBER() OVER(PARTITION BY c.comment_id_no 
                                      ORDER BY c.inserted_at DESC) AS RowNumber
            FROM    Comments AS c
        ) AS c
WHERE   c.RowNumber = 1
AND     c.show = 'true';

既然你已经用Postgresql做了标记,你也可以使用DISTINCT ON ():

SELECT  *
FROM    (   SELECT  DISTINCT ON (c.comment_id_no) 
                    c.id, c.comment_id_no, c.text, c.show, c.inserted_at
            FROM    Comments AS c 
            ORDER By c.comment_id_no, inserted_at DESC
        ) x
WHERE   show = 'true';

Examples on DB<>Fiddle

Postgresql相关问答推荐

如何在gorm中创建一个可读但不可写的字段

使用多个分隔符拆分SQL

为什么在PostgreSQL中CPU_INDEX_TUPLE_COST与CPU_TUPLE_COST不同

DBT-DBT依赖于未找到的源

无法继承BYPASSRLS

Postgres 11没有强制执行外键约束?

PostGresql :正则表达式 Select 其中只有一个正斜杠的行

具有有限字母表的自定义字符串类型

如何在typeorm和嵌套js中将运行时变量设置为postgresql

TimescaleDB 连续聚合:如何存储连续聚合结果

查找列中的数据是否满足sql中的数据类型条件

MERGE 语句的锁定级别

如何获得区间的绝对值

Rails 重置所有 Postgres 序列?

PostgreSQL 中的 JSON 外键

如何在 plpgsql 中使用记录类型变量?

在 MAC OS X 10.6 for PostgreSQL 上设置 SHMMAX 等值

PGError:错误: column of relation does not exist

SQLAlchemy 声明式:定义触发器和索引 (Postgres 9)

使用 SQLAlchemy 进行 PostgreSQL ILIKE 查询