繁体   English   中英

如何在 Postgres sql 中按相似的 integer 值分组?

[英]How to group by similar integer values in Postgres sql?

我有一个非常简单的数据库表,每次扫描产品(RFID 扫描仪)时都会插入一个新条目。

扫描表:

身份证(公钥) Product_ID (FK) 创建时间
1个 1个 2023-01-26 10:39:00.0000
2个 2个 2023-01-26 10:39:02.0000
3个 3个 2023-01-26 10:39:04.0000
4个 4个 2023-01-26 10:47:00.0000

我的目标是在产品 ID 被扫描时以指定的容差(以秒为单位)对产品 ID 进行聚类,因此例如对于我表中的条目和 10 秒的容差,所需的结果将是

Product_IDs
{1, 2, 3}
{4}

我第一次尝试解决这个问题是这样的:

SELECT ARRAY_AGG(DISTINCT Product_ID) FROM scans GROUP BY ROUND(EXTRACT(EPOCH FROM created_at) / 10);

这种方法有点奏效,但在极端情况下,例如,当一个产品在第 19 秒被扫描而另一个产品在第 21 秒被扫描时,它不会被组合在一起,尽管它应该被组合在一起。

有什么更好、更可靠的方法来解决这个问题?

如果行之间的时间超过 10 秒,我将假设这些组是分开的。 例如测试数据

create table scans(ID int,  Product_ID int, Created_At TimeStamp);
insert into scans values
 (1,    1,cast('2023-01-26 10:39:00.000' as TimeStamp))
,(2,    2,cast('2023-01-26 10:39:02.000' as TimeStamp))
,(3,    3,cast('2023-01-26 10:39:11.000' as TimeStamp))
,(4,    4,cast('2023-01-26 10:47:00.000' as TimeStamp))
;

计算当前行和前一行之间的时间差。 当差异大于“10 秒”时 - 即开始新的扫描组。

with ScansDif as(
  select * 
    ,Created_At-lag(Created_At,1,Created_At)over(order by Created_At) dif
  from scans
)
,ScansGroup as(
  select * 
     ,sum(case when dif>cast('10'||' second' as interval) then 1 else 0 end)
          over(order by Created_At rows unbounded preceding) grN
  from ScansDif
)
SELECT ARRAY_AGG(DISTINCT Product_ID) 
FROM ScansGroup 
GROUP BY grn

组号

ID 产品编号 创建时间 差异 grn
1个 1个 2023-01-26 10:39:00 00:00:00 0
2个 2个 2023-01-26 10:39:02 00:00:02 0
3个 3个 2023-01-26 10:39:11 00:00:09 0
4个 4个 2023-01-26 10:47:00 00:07:56 1个

组 0 的第一行和最后一行之间的时间差是 00:11。 结果

array_agg
{1,2,3}
{4}

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM