在 WHERE 子句中使用子查询,但每个子查询结果限制为一个匹配项

Using a subquery to in WHERE clause but limiting to one match per sub query result

我正在使用 MariaDB。

我有两个 table,REPLEN 存储销售的产品、数量和销售日期等,另一个是主要的产品 table,包含描述、库存代码、库存数量、最后日期交付等。STOCK_CODE 很重要,因为相同的匹配项由该产品的替代品共享。

我想使用此库存代码查找 REPLEN 中现在缺货但有库存的任何条目的替代品。我想将此限制为每场比赛一个替代方案,并且该替代方案是为库存轮换目的交付的最旧的替代方案。

table 看起来像这样:

补充:

PROD_ID     QTY_SOLD   DATE_LAST_SOLD
4552        6          2020-10-28
8612        2          2020-11-14
7661        1          2020-11-15
9891        5          2020-11-17

这是通过 PROD_ID KEY 与产品 table 相关联的

PRODUCT_ID   DESCRIPTION             STOCK_CODE     STOCK_QTY   DATE_LDELIV
4552         Cashew Nuts Best Buy    NUTS CASHEW       0         2020-11-01
8612         Baked Beans SaveMore    BEANS BUDGET      0         2020-08-12
7661         Nestle Instant Coffee   COFFEE INSTANT    40        2020-10-20
9891         Heinz Baked Beans       BEANS HEINZ       12        2020-10-09
10988        Baked Beans Supersaver  BEANS BUDGET      10        2020-11-04
11092        Baked Beans BestBuy     BEANS BUDGET      14        2020-10-27
12093        Cashew Nuts Supersaver  NUTS CASHEW       24        2020-11-18  

现在产品 4552 和 8612 缺货,所以告诉别人补货没有任何意义。但是,我真的不在乎货架上有什么品牌的预算豆或腰果,所以其他两种产品也共享 BEANS BUDGET stock_code 和 1 个其他产品共享 NUTS CASHEW 所有这些都有库存。

我想要一个 SELECT QUERY 来找到它们!

所以首先我有一个查询,查找 REPLEN 中没有库存的任何产品的所有 STOCK_CODE

SELECT p.STOCK_CODE FROM product p JOIN replen r ON p.PRODUCT_ID=r.PROD_ID WHERE p.STOCK_QTY <=0

这个returns“BEANS_BUDGET”和“NUTS CASHEW”

然后我可以将其用作子查询来查找有货的产品并共享 Stock_code

SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV FROM product p 
WHERE p.STOCK_CODE IN 
  (SELECT p.STOCK_CODE FROM product p 
  JOIN replen r ON p.PRODUCT_ID=r.PROD_ID 
  WHERE p.STOCK_QTY <=0) 
AND p.STOCK_QTY > 0

但是这 return 所有替代产品:

PRODUCT_ID     STOCK_CODE     DATE_LDELIV
10988          BEANS BUDGET   2020-11-04
11092          BEANS BUDGET   2020-10-27
12093          NUTS CASHEW    2020-11-18 

我的架子上只有 space 一排 Budget Bean!

这就是我卡住的地方。我可以添加 GROUP BY:

SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV FROM product p 
WHERE p.STOCK_CODE IN 
  (SELECT p.STOCK_CODE FROM product p 
  JOIN replen r ON p.PRODUCT_ID=r.PROD_ID 
  WHERE p.STOCK_QTY <=0) 
AND p.STOCK_QTY > 0 GROUP BY STOCK_CODE 

但是这个 returns:

PRODUCT_ID     STOCK_CODE     DATE_LDELIV
10988          BEANS BUDGET   2020-11-04
12093          NUTS CASHEW    2020-11-18 

问题是产品 11092 是旧库存,所以我希望 returned 而不是 10988。

我不能在 GROUP BY 之前使用 ORDER BY。即使我可以(通过使用别名将查询包装在另一个查询中)它总是 returns 10988 因为 MariaDB 在设计上忽略了子查询结果中的任何顺序。

需要的是一个查询,该查询将 return 只有一种选择,即 OLDEST Delivered 产品。本质上,我希望它 return:

PRODUCT_ID     STOCK_CODE     DATE_LDELIV
11092          BEANS BUDGET   2020-10-27
12093          NUTS CASHEW    2020-11-18 

求助!

您可以应用 ROW_NUMBER 来获取最早日期的行:

SELECT *
FROM
 (
    SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV,
       ROW_NUMBER() OVER (PARTITION BY STOCK_CODE ORDER BY DATE_LDELIV) as rn
    FROM product p
    WHERE p.STOCK_CODE IN 
      (SELECT p.STOCK_CODE FROM product p 
      JOIN replen r ON p.PRODUCT_ID=r.PROD_ID 
      WHERE p.STOCK_QTY <=0) 
    AND p.STOCK_QTY > 0
 ) as dt
WHERE rn = 1

让我们从这个几乎有效的查询开始:

SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV
FROM product p JOIN
WHERE p.STOCK_CODE IN (SELECT p.STOCK_CODE
                       FROM product p JOIN
                           replen r
                           ON p.PRODUCT_ID = r.PROD_ID 
                       WHERE p.STOCK_QTY <= 0
                      ) AND
     p.STOCK_QTY > 0

接下来,我将加入 replen table 以获取最早的日期:

SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV, r.date_last_sold,
       ROW_NUMBER() OVER (PARTITION BY p.PRODUCT_ID ORDER BY r.date_last_sold) as seqnum
FROM product p JOIN
     replen r
     ON p.PRODUCT_ID = r.PROD_ID 
WHERE p.STOCK_CODE IN (SELECT p.STOCK_CODE
                       FROM product p JOIN
                            replen r
                            ON p.PRODUCT_ID = r.PROD_ID 
                       WHERE p.STOCK_QTY <= 0
                      ) AND
     p.STOCK_QTY > 0;

然后将其用作子查询以获取所需的每个产品一行:

SELECT p.*
FROM (SELECT p.PRODUCT_ID, p.STOCK_CODE, p.DATE_LDELIV, r.date_last_sold,
             ROW_NUMBER() OVER (PARTITION BY p.PRODUCT_ID ORDER BY r.date_last_sold) as seqnum
      FROM product p JOIN
           replen r
           ON p.PRODUCT_ID = r.PROD_ID 
      WHERE p.STOCK_CODE IN (SELECT p.STOCK_CODE
                             FROM product p JOIN
                                  replen r
                                  ON p.PRODUCT_ID = r.PROD_ID 
                             WHERE p.STOCK_QTY <= 0
                            ) AND
           p.STOCK_QTY > 0
     ) p
WHERE seqnum = 1;