有没有办法确保在DISTINCT之后发生WHERE子句?

Rob*_*ion 25 sql postgresql distinct elixir where

想象一下comments,您的数据库中有一个表.

注释表有列,id,text,show,comment_id_no.

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

| id |  comment_id_no | text | show | inserted_at |
| -- | -------------- | ---- | ---- | ----------- |
| 1  | 1              | hi   | true | 1/1/2000    |
Run Code Online (Sandbox Code Playgroud)

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

| id |  comment_id_no | text | show | inserted_at |
| -- | -------------- | ---- | ---- | ----------- |
| 1  | 1              | hi   | true | 1/1/2000    |
| 2  | 1              | hey  | true | 1/1/2001    |
Run Code Online (Sandbox Code Playgroud)

注意它保持不变comment_id_no.这样我们就可以看到评论的历史了.

现在用户决定他们不再想要显示他们的评论

| 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    |
Run Code Online (Sandbox Code Playgroud)

这隐藏了最终用户的评论.

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

| 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    |
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 选择所有最新的,不同的comment_id_nos.(应返回id=3id=4)
  2. 选择show = true(应该只返回id=4)

注意:我实际上是使用ecto在elixir中编写此查询,并且希望能够在不使用子查询函数的情况下执行此操作.如果有人能在sql中回答这个问题,我可以自己转换答案.如果有人知道如何在灵药中回答这个问题,那么也随时回答.

Gar*_*thD 14

您可以在不使用子查询的情况下执行此操作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';
Run Code Online (Sandbox Code Playgroud)

我认为所有其他方法都需要某种子查询,这通常是通过排名函数完成的:

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';
Run Code Online (Sandbox Code Playgroud)

由于您已使用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';
Run Code Online (Sandbox Code Playgroud)

DB <>小提琴的例子


Gor*_*off 5

我想你想要:

select c.*
from comments c
where c.inserted_at = (select max(c2.inserted_at)
                       from comments c2
                       where c2.comment_id_no = c.comment_id_no
                      ) and
      c.show = 'true';
Run Code Online (Sandbox Code Playgroud)

我不明白这有什么关系select distinct。您只需要评论的最后一个版本,然后检查是否可以显示该版本。

编辑:

在 Postgres 中,我会这样做:

select c.*
from (select distinct on (comment_id_no) c.*
      from comments c
      order by c.comment_id_no, c.inserted_at desc
     ) c
where c.show
Run Code Online (Sandbox Code Playgroud)

distinct on通常具有相当好的性能特征。