我想选择只有ID为1,2,3的产品的订单,是否可能:
这是我的实际SQL查询:
SELECT COUNT(*) FROM "orders"
INNER JOIN "line_items" ON "line_items"."order_id" = "orders"."id"
INNER JOIN "products" ON "products"."id" = "line_items"."product_id"
WHERE "products"."id" IN (1, 2, 3)
GROUP BY orders.id
HAVING (only line items with these products ids ?)
有什么想法吗?
例如:
Order with products 1, 2 => OK
Order with products 1, 3 => OK
Order with products 1, 2, 3 => OK
Order with products 1, 4 => NOT OK
Order with products 1, 2, 3, 4 => NOT OK
答案 0 :(得分:1)
我最终使用PostgreSQL中的array_agg
并且<@
包含函数:
SELECT orders.id FROM "orders"
INNER JOIN "line_items" ON "line_items"."order_id" = "orders"."id"
GROUP BY orders.id
HAVING array_agg(line_items.product_id) <@ ARRAY[1, 2, 3];
答案 1 :(得分:1)
虽然your presented solution有效(假设UNIQUE
约束你保守秘密),但更大的表格会 痛苦地慢 。它不能使用索引,因此必须在Postgres应用过滤器之前聚合整个表line_items
。
改为使用:
SELECT o.*
FROM (
SELECT DISTINCT i.order_id
FROM line_items i
WHERE i.product_id IN (1,2,3)
AND NOT EXISTS (
SELECT 1 FROM line_items
WHERE order_id = i.order_id
AND product_id NOT IN (1,2,3)
)
) i
JOIN orders o ON o.id = i.order_id;
这可以使用索引,并且通常会快几个数量级(差异随着表的大小而增长)。通常,product_id
,order_id
为整数列,这两个多列索引为perfect
:
CREATE INDEX foo1_idx ON line_items (product_id, order_id);
CREATE INDEX foo2_idx ON line_items (order_id, product_id);
其中一个可能已经是主键,那么你只需要添加另一个。假设orders.id
也被编入索引。所有这一切都应该在你的问题中。
为什么这些指数?关于dba.SE的相关答案的详细解释:
Is a composite index also good for queries on the first field?
这是 relational division 的情况。我们在这个问题下汇集了一系列技术:
How to filter SQL results in a has-many-through relation
这里的特殊困难是允许各种组合。结果更容易通过 not 允许来定义。
除此之外:不要不必要地双重引用合法的小写identifiers。使代码嘈杂且难以阅读。
答案 2 :(得分:0)
添加如下WHERE子句:
SELECT COUNT(*) FROM "orders"
INNER JOIN "line_items" ON "line_items"."order_id" = "orders"."id"
INNER JOIN "products" ON "products"."id" = "line_items"."product_id"
WHERE "products"."id" IN (1, 2, 3)
AND "line_items"."product_id" IN (1,2,3)
GROUP BY orders.id