PostgreSQL 1到n关系,查询行,其中n与输入完全匹配

PostgreSQL 1到n关系,查询行,其中n与输入完全匹配,postgresql,relational-division,Postgresql,Relational Division,假设我有两张桌子,订单和订单详情。订单详细信息包含订单中订购的产品。为清楚起见,下面有一个示例: 订单: +----------+ | order_id | +----------+ | 1 | | 2 | | 3 | | 4 | | 5 | +----------+ 订单详情: +----------+-------------+ | order_id | product_id | +----------+-------

假设我有两张桌子,订单和订单详情。订单详细信息包含订单中订购的产品。为清楚起见,下面有一个示例:

订单:

+----------+
| order_id |
+----------+
|        1 |
|        2 |
|        3 |
|        4 |
|        5 |
+----------+
订单详情:

+----------+-------------+
| order_id |  product_id |
+----------+-------------+
|        1 |           1 |
|        1 |           4 |
|        2 |           3 |
|        2 |           4 |
|        3 |           3 |
|        3 |           4 |
|        3 |           5 |
|        4 |           4 |
|        4 |           3 |
+----------+-------------+
如何找到与产品列表完全匹配的订单? 根据上述数据,给定产品列表[3,4],查询应返回两个订单,即2和4。订单3不匹配,因为产品5也已订购

我可以这样做,但感觉好像我错过了什么:

select order_id
from orders_details
group by order_id
having array_agg(product_id) @> array[3, 4] and array_agg(product_id) <@ array[3, 4]

我不太熟悉Postgres的数组语法,但您可以通过使用两个断言的聚合来处理此问题:

SELECT o.order_id
FROM Orders o
INNER JOIN Orders_details od
    ON o.order_id = od.order_id
GROUP BY
    o.order_id
HAVING
    COUNT(CASE WHEN od.product_id NOT IN (3, 4) THEN 1 END) = 0 AND
    COUNT(DISTINCT od.product_id) = 2;

HAVING子句中的第一个计数断言,除了3和4之外,没有其他产品标识出现。但这仍然会导致订单只有一个产品id。HAVING子句中的第二个计数断言,实际上存在两个产品id,这意味着是3和4。

附加问题:这个特定问题有名称吗?是的,它有名称,甚至有标记。我认为数组解决方案可能是Postgres中最有效的一种。或者,您可以使用按product\u id=array[3,4]排序的array\u aggproduct\u id