我在Postgres 9.5数据库中有4个表格,用于向具有以下表格结构的客户发送通知:
notices
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一样。我尝试使用notice_details
获取group by notice_id, customer_id
表格中的最后一个插入行并获取已发送的order_num
,但这不会涵盖所有情况。
我还尝试跳过那些已经发送过的行,但这些行也没有涵盖这个场景。
我怎么能管理它?
答案 0 :(得分:1)
假设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;
它返回的文档的下一个notice_document_id
高于为每个客户和通知组合发送的最高文档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;