给定一组 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_idsorder_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),bdistinct 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) 上的另一个索引。见:

Is a composite index also good for queries on the first field?

关于数组字面量的手册:

https://www.postgresql.org/docs/current/arrays.html#ARRAYS-INPUT

关于ANYALL 构造:

IN vs ANY operator in PostgreSQL https://www.postgresql.org/docs/current/functions-subquery.html

【讨论】:

orders 停课一周:/ 如果没有第三张桌子,您将如何解决? @mitchell-reynolds:我添加了另一个查询。 我第一次看到('a,b,c') 的用法,语法是否允许带有空格或奇数字符的字符串?像('a,b,c, a-b-c') 这样说,其中“a-b-c”是一个 ID @mitchell-reynolds:这是一个数组literal。带空格的字符串必须用双引号括起来。我在上面添加了一些链接。【参考方案2】:

我们需要定义与您的要求相反的内容并对其进行过滤。那么,哪些订单有至少一笔交易不在a,b,c 中。我们统计订单分组中此类交易的数量,过滤掉COUNT &gt; 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 的订单子集的主要内容,如果未能解决你的问题,请参考以下文章

字符串转 多行 ,判断给定一组id ,查库中不存在用

c_cpp 给定一组数字,返回所有可能的排列。例如,[1,2,3]具有以下排列:[1,2,3],[1,3,2],[2

SQL 查询每个组 ID 仅返回 1 条记录

Mysql - 仅返回具有相同唯一 ID 的第一行

如何从 WooCommerce 中的订单项中获取产品类别 ID

MySQL查询仅返回具有计数的重复条目