选择具有不同字段的最后一行

Posted

技术标签:

【中文标题】选择具有不同字段的最后一行【英文标题】:Select Last Rows with Distinct Field 【发布时间】:2021-01-25 12:24:44 【问题描述】:

我有一个具有以下架构的表:

id itemid date        some additional data
1   1000  10/12/2020       a
2   1000  10/12/2020       b
3   1002  09/12/2020       c
4   1001  07/12/2020       d
5   1000  05/12/2020       e
6   1005  03/12/2020       f
7   1003  03/12/2020       g

在此表中,只有 id 字段是唯一的。我关心的是获取包含最后一个 X 不同 itemid 的行,按日期排序。

例如,在上面的示例中,如果我想获得最后 3 个不同的 itemid,我将获得前 4 行,因为在前 4 行中我们有三个不同的 itemid: 1000、1002 和 1001。我不确定如何使用单个 SQL 语句来实现。

【问题讨论】:

我不明白这个。如果您想获得不同的 itemid,那么您为什么期望前 4 行会重复 itemid = 1000 表中有不同的第 1 行和第 2 行的附加字段 - 我关心的是获取与最后 X 个不同 itemid 相关的所有数据 - 让我更新架构。 请注意,表格有,而不是字段。 是的,我的错.... 【参考方案1】:

如果我理解正确,您想计算每行(按日期)的不同项目 ID 的数量,并返回计数为 3 的所有行。

如果 Postgres 支持这个,你可以使用:

select t.*
from (select t.*, 
             count(*) filter (where id = min_id) over (order by date desc) as cnt_itemid
      from (select t.*,
                   min(id) over (partition by itemid order by date desc) as min_id
            from t
           ) t
     ) t
where cnt_itemid <= 3;

唉,Postgres 不支持 COUNT(DISTINCT) 作为窗口函数。但是你可以使用DENSE_RANK()来计算它:

select t.*
from (select t.*, 
             count(*) over (filter where id = min_id) as cnt_itemid
      from (select t.*,
                   min(id) over (partition by itemid order by date) as min_id
            from t
           ) t
     ) t
where cnt_itemid <= 3;

但是,这会返回所有在第 4 项之前的最新行——因此它有额外的行。

要获得四行,您需要项目 id 为“3”的第一行。一种方法是:

select t.*
from (select t.*, min(id) filter (where cnt_itemid = 3) over () as min_cnt_itemid_3
      from (select t.*, 
                   count(*) filter (where id = min_id) over (order by date desc) as cnt_itemid
            from (select t.*,
                         min(id) over (partition by itemid order by date desc) as min_id
                  from t
                 ) t
           ) t
     ) t
where id <= min_cnt_itemid_3;

您也可以通过识别“第三项”的第一次出现然后选择该行之前的所有行来做到这一点:

select t.*
from t join
     (select itemid, min(max_date) over () as min_max_date
      from (select t.itemid, max(date) as max_date
            from t
            group by t.itemid
            order by max(t.date) desc
            limit 3
           ) t
      ) tt
      on t.itemid = tt.itemid and t.date >= tt.min_max_date;

This fiddle 显示其中的每一个。

【讨论】:

三个只是我用来说明示例的数字 - 我想要实现的是获取有关最后 X 个不同 itemid 的所有数据 - 让我举例说明 - 假设 itemid 是文章并且此表中的行代表文章上的 cmets,我想获取最近 X 篇文章上的所有 cmets(行)。例如 - 最近 20 篇文章中的所有 cmets。 因此查询将是“按日期降序排列表格,继续选择行,直到计算出 X 个不同的 itemid”【参考方案2】:

您可以按如下方式使用解析函数:

select * from
(select t.*,
       conut(distinct item_id) over (order by date desc) as cnt
  from your_Table t) t
 where cnt <= 3

【讨论】:

以上是关于选择具有不同字段的最后一行的主要内容,如果未能解决你的问题,请参考以下文章

使用具有不同 order by 子句的 postgres 窗口函数

在一个查询Access数据库中从具有不同字段的两个不同表中选择列

当 unpivot 未检测到具有不同类型的字段时,雪花如何转换选择查询的所有字段?

如何计算SQL中一行中的不同字段

如何从具有最后时间戳的数据框中选择不同的记录

如何在R中的一列中添加具有不同值的新行