sql - 按 order_num 字段查找下一个连续行

标签 sql database postgresql greatest-n-per-group

我在 Postgres 9.5 数据库中有 4 个表用于向具有以下表结构的客户发送通知:

通知

id    name     
--------------
111   notice1  
112   notice2
113   notice3

notice_documents - 单个通知可以包含多个文档,其中 order_num 递增。

id    notice_id   name   order_num    
----------------------------------
211   111         doc1   1
212   111         doc2   2
213   111         doc2   3
214   112         doc3   1
215   113         doc4   1
216   113         doc5   2
217   113         doc6   3
218   113         doc7   4

notice_details - 这个表有发送通知文件的记录。 is_archived = 0 表示它是事件的并且只考虑那些记录。

id   customer_id   notice_id   notice_document_id   is_archived
1    3133          111         211                  0
2    3133          111         212                  0
3    3134          112         214                  0
4    3135          113         216                  0

customers - 每个客户都有一个 notice_id 用于发送文档。

id   customer_name notice_id
3133 abc           111
3134 xyz           112
3135 pqr           113

所有列都定义为 NOT NULL,并且参照完整性通过 FK 约束强制执行。

我需要为客户获取连续或下一个文档:

  1. 如果我发送了前两个文档(如 order_num = 12),那么下一个文档将是第三个(order_num = 3 >) - 例如示例中的客户 3133。
  2. 如果我直接发送了第二份文件(例如 order_num = 2,那么下一份文件也将是第三份文件 - 例如客户 3135。
  3. 如果最后一份文件已经发送,则不要发送任何文件。
  4. 如果尚未发送文件,则发送第一个文件。

我尝试使用 group by notice_id, customer_id 获取 notice_details 表中最后插入的行并获取发送的 order_num 但那赢了涵盖所有场景。
我还尝试跳过那些已经发送但也不涵盖该场景的行。

我该如何管理?

最佳答案

假设 notice_documents.idorder_num 单调递增(这使得列 order_num 冗余噪声),这应该满足所有要求:

SELECT DISTINCT ON (c.id, ndo.notice_id)
       c.id AS customer_id, notice_id, ndo.id AS notice_document_id
FROM   customers             c
JOIN   notice_documents ndo USING (notice_id)
WHERE  NOT EXISTS (
   SELECT 1
   FROM   notice_details 
   WHERE  customer_id = c.id
   AND    notice_id   = c.notice_id
   AND    is_archived  -- "consider those records only"
   AND    notice_document_id >= ndo.id
   )
ORDER  BY c.id, notice_id, ndo.id;

它返回比已为每个客户和通知组合发送的最高文档 ID 更高的 notice_document_id 的文档。 (没有任何文件已经发送。)

如果您有并发访问,则需要采取更多措施来避免竞争条件。相关:

关于 DISTINCT ON:

如何排除已经从另一个表中引用的行:

对于单个给定的customer_id(解决问题更新)更简单:

SELECT DISTINCT ON (notice_id)
       notice_id, ndo.id AS notice_document_id
FROM   customers        c
JOIN   notice_documents ndo USING (notice_id)
WHERE  c.customer_id = $customer_id  -- input customer here
WHERE  NOT EXISTS (
   SELECT 1
   FROM   notice_details 
   WHERE  customer_id = c.id
   AND    notice_id   = c.notice_id
   AND    is_archived  -- "consider those records only"
   AND    notice_document_id >= ndo.id
   )
ORDER  BY notice_id, ndo.id;

关于sql - 按 order_num 字段查找下一个连续行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43954777/

相关文章:

MySQL:使用另一个映射表从旧表向新表插入值

python - 使用 pyodbc 创建数据库

java - EclipseLink 2.3.3 无法更新 PostgreSQL 上的版本化实体

sql - 如何在 Hibernate 中使用数组字段创建条件

sql - 当列名是数字时,使用 VB.NET 中的 ADO 查询 Excel

mysql - 如何优化这个mysql查询?运行缓慢

django - 将字段添加到 Django 的现有数据库中(版本 < 1.7)

database - 实体关系图。 IS A 关系如何转化为表?

postgresql - heroku pgbackups :restore: Invalid dump format

php - 我应该使用 SQL 还是 XML?