我在 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 约束强制执行。
我需要为客户获取连续或下一个文档:
- 如果我发送了前两个文档(如
order_num = 1
和2
),那么下一个文档将是第三个(order_num = 3
>) - 例如示例中的客户 3133。 - 如果我直接发送了第二份文件(例如
order_num = 2
,那么下一份文件也将是第三份文件 - 例如客户 3135。 - 如果最后一份文件已经发送,则不要发送任何文件。
- 如果尚未发送文件,则发送第一个文件。
我尝试使用 group by notice_id, customer_id
获取 notice_details
表中最后插入的行并获取发送的 order_num
但那赢了涵盖所有场景。
我还尝试跳过那些已经发送但也不涵盖该场景的行。
我该如何管理?
最佳答案
假设 notice_documents.id
随 order_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/