给定一组 ID,返回仅具有这些 ID 的订单子集
Posted
技术标签:
【中文标题】给定一组 ID,返回仅具有这些 ID 的订单子集【英文标题】:Given a set of IDs, Return the Subset of Orders with only those IDs 【发布时间】:2021-01-26 04:15:24 【问题描述】:给定一组product_ids
,只有有那些product_ids
的order_ids
是什么?
对于下面的示例,我只想要具有(a,b,c)
某种组合的 order_id。我有 2 个如下表:
“交易”表:
order_id | product_id |
---------+-------------
1 | a |
1 | b |
2 | a |
2 | X |
3 | a |
3 | b |
3 | c |
... | ... |
999 | Y |
“产品”表:
product_id |
------------
a |
b |
c |
d |
X |
Y |
... |
ZZZ |
Desired Output 有 2 个带有预期表输出的 order_id:
order_id |
----------
1 |
3 |
注意order_id == 2
已被删除,虽然它有product_id == a
,但因为它有product_id == X
,所以它应该被删除。
因此这并不简单:
SELECT DISTINCT(order_id)
FROM transactions
WHERE product_id IN (a, b, c)
【问题讨论】:
与您的问题无关,但是:distinct
不是一个函数。它始终适用于选择列表中的所有列。用括号括住其中一列不会改变任何东西并且是无用的。 distinct (a),b
与 distinct a,(b)
或 distinct a,b
相同
【参考方案1】:
通常,有一个 orders
表与之配套,每个订单只有一行。
如果我们可以进一步假设每个订单总是至少有一笔交易,那么这样就可以了:
SELECT o.id
FROM orders o
WHERE NOT EXISTS (
SELECT FROM transactions -- SELECT list can be empty for EXISTS test
WHERE order_id = o.id
AND product_id <> ALL ('a,b,c')
);
这对于非常常见的 product_id 或长列表很有用。
对于短名单或稀有产品,首先从正面选择开始会更快。喜欢:
SELECT order_id
FROM (
SELECT DISTINCT order_id
FROM transactions
WHERE product_id = ANY ('a,b,c')
) t
WHERE NOT EXISTS (
SELECT FROM transactions
WHERE order_id = t.order_id
AND product_id <> ALL ('a,b,c')
);
(product_id)
上的索引对于性能至关重要。更好的是,(product_id, order_id)
上的多列索引,以及(order_id, product_id)
上的另一个索引。见:
关于数组字面量的手册:
https://www.postgresql.org/docs/current/arrays.html#ARRAYS-INPUT关于ANY
和ALL
构造:
【讨论】:
orders
停课一周:/ 如果没有第三张桌子,您将如何解决?
@mitchell-reynolds:我添加了另一个查询。
我第一次看到('a,b,c')
的用法,语法是否允许带有空格或奇数字符的字符串?像('a,b,c, a-b-c')
这样说,其中“a-b-c”是一个 ID
@mitchell-reynolds:这是一个数组literal。带空格的字符串必须用双引号括起来。我在上面添加了一些链接。【参考方案2】:
我们需要定义与您的要求相反的内容并对其进行过滤。那么,哪些订单有至少一笔交易不在a,b,c
中。我们统计订单分组中此类交易的数量,过滤掉COUNT > 0
的订单,只返回COUNT = 0
的订单。
SELECT order_id
FROM transactions
GROUP BY order_id
HAVING COUNT(CASE WHEN product_id NOT IN (a, b, c) THEN 1 END) = 0
如果您将 a,b,c
作为另一个表中的产品列表,并且您想过滤而不是硬编码到查询中,那么它会稍微复杂一些:
SELECT order_id
FROM transactions AS t
LEFT JOIN listOfProducts AS l ON l.product_id = t.product_id
GROUP BY order_id
HAVING COUNT(CASE WHEN l.product_id IS NULL THEN 1 END) = 0
【讨论】:
第二部分的myList
是什么? myList = (a, b, c)
?还是不是(a, b, c)
列表?
a,b,c
从表中而不是直接在查询中。已澄清以上是关于给定一组 ID,返回仅具有这些 ID 的订单子集的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 给定一组数字,返回所有可能的排列。例如,[1,2,3]具有以下排列:[1,2,3],[1,3,2],[2