简体   繁体   English

具有小于/大于条件的 MYSQL JOIN(minimum_quantity,valid_from)

[英]MYSQL JOIN with lower-than / greater-than conditions (minimum_quantity, valid_from)

I have我有

  1. order table with columns带列的order
    • id
    • date
    • supplier_id
  2. order_lineitem table with columns带有列的order_lineitem
    • id
    • order_id
    • article_id
    • order_quantity
    • order_price
  3. a prices table with columns带有列的prices
    • id
    • article_id
    • supplier_id
    • valid_until
    • minimum_order_quantity
    • list_price

The prices table doesn't necessarily have to have a matching / valid entry, so this one would have to be joined via an outer join.价格表不一定必须有一个匹配/有效的条目,所以这个必须通过外部连接来连接。

I'd like to compare order_price s against list_price s.我想比较order_pricelist_price

Therefore I need to somehow join因此我需要以某种方式加入

SELECT 
   o.id,
   o.date,
   ol.article_id,
   ol.order_quantity,
   ol.order_price,
   p.list_price
FROM 
   `order` o JOIN order_lineitem ol on ol.order_id = o.id
   LEFT OUTER JOIN prices p on 
           p.article_id = ol.article_id
       AND p.supplier_id = o.supplier_id
       AND p.minimum_order_quantity <= ol.order_quantity
       AND IFNULL(p.valid_until, DATE('2099-12-31')) >= o.date
       /* here comes the fun part that doesn't work (reliably) */
       ORDER BY 
          IFNULL(p.valid_until, DATE('2099-12-31')) asc,
          p.minimum_order_quantity desc
       GROUP BY o.id, ol.id, p.article_id
       /* ... trying to get only THAT price from the prices table that applies for the 
          (a) the given article
          (b) from the given supplier
          (c) that was valid at the time of purchase (i.e. has the smallest "valid_until" date that is greater than the purchase date)
          (d) when ordering the given quantity (prices can also increase with higher quantities, so it has to be the price with the largest minimum_order_quantity that is smaller than the ordered quantity)
       */

I particularly don't want to fall into the trap (which I dug for myself here) of using group by to limit the results to 1 record from the prices table based on a previous sorting, since我特别不想陷入使用 group by 根据先前排序将结果限制为价格表中的 1 条记录的陷阱(我在这里为自己挖的),因为

(i) as per MySQL documentation it is non-deterministic which record will actually get returned (although it may in effect often work and this is a frequently suggested route to go) - also see this excellent explanation on the issue: https://stackoverflow.com/a/14770936/9818188 and (i) 根据 MySQL 文档,实际返回哪个记录是不确定的(尽管它可能实际上经常工作,这是一个经常建议的路线) - 另请参阅有关该问题的出色解释: https:// stackoverflow.com/a/14770936/9818188

(ii) this concept wouldn't work on other SQL implementations like SQL Server, Maria DB & Co. (ii) 这个概念不适用于其他 SQL 实现,如 SQL Server、Maria DB & Co。

The question is not around putting in a nested query in order to be able to ORDER first and then GROUP subsequently.问题不在于放入嵌套查询以便能够先排序,然后再进行分组。 It's more about how to really properly get the correct row--ideally also working on other SQL implementations like SQL Server, Maria DB or Google BigQuery.它更多的是关于如何真正正确地获得正确的行——理想情况下,还可以在其他 SQL 实现上工作,如 SQL Server、Maria DB 或 Google BigQuery。

And since I can't really rely on prices being cheaper the more I buy I also can't simply get the min(list_price).而且由于我不能真正依赖价格越便宜,我买的越多,我也不能简单地获得 min(list_price)。

How can this can be achieved?怎样才能做到这一点?

Since the output of this query is required for downstream processing, I can't slice & dice the task but need a full list of all orders with respective list prices.由于下游处理需要此查询的输出,因此我无法对任务进行切片和切块,但需要所有订单的完整列表以及相应的标价。

EDIT Here is a SQL fiddle - the desired prices are shown in column order_price , the prices incorrectly determined by the JOIN (excluding the order by clause - as this would cause non-deterministic results) are shown in column list_price : http://sqlfiddle.com/#!9/f03a4f/2编辑这是一个 SQL 小提琴 - 所需的价格显示在order_price列中,JOIN 错误确定的价格(不包括order by子句 - 因为这会导致不确定的结果)显示在list_price列中: http://sqlfiddle .com/#!9/f03a4f/2



CREATE TABLE `order`
    (`id` int, `date` datetime, `supplier_id` int)
;
    
INSERT INTO `order`
    (`id`, `date`, `supplier_id`)
VALUES
    (1, '2022-01-15 00:00:00', 1),
    (2, '2022-02-15 00:00:00', 1),
    (3, '2022-03-15 00:00:00', 1),
    (4, '2022-01-15 00:00:00', 2),
    (5, '2022-02-15 00:00:00', 2),
    (6, '2022-03-15 00:00:00', 2)
;


CREATE TABLE order_lineitem
    (`id` int, `order_id` int, `article_id` int, `order_quantity` int, `order_price` int)
;
    
INSERT INTO order_lineitem
    (`id`, `order_id`, `article_id`, `order_quantity`, `order_price`)
VALUES
    (1, 1, 1, 1, 11),
    (2, 1, 1, 10, 8),
    (3, 1, 1, 100, 9),
    (4, 2, 1, 1, 15),
    (5, 2, 1, 10, 12),
    (6, 2, 1, 100, 13),
    (7, 3, 1, 1, 17),
    (8, 3, 1, 10, 14),
    (9, 3, 1, 100, 16),
    (10, 4, 1, 1, 10),
    (11, 4, 1, 10, 80),
    (12, 4, 1, 100, 80),
    (13, 5, 1, 1, 10),
    (14, 5, 1, 10, 80),
    (15, 5, 1, 100, 80),
    (16, 6, 1, 1, 10),
    (17, 6, 1, 10, 10),
    (18, 6, 1, 100, 10)
;


CREATE TABLE prices
    (`id` int, `article_id` int, `supplier_id` int, `valid_until` varchar(10), `minimum_order_quantity` int, `list_price` int)
;
    
INSERT INTO prices
    (`id`, `article_id`, `supplier_id`, `valid_until`, `minimum_order_quantity`, `list_price`)
VALUES
    (1, 1, 1, '2022-01-31', 1, 11),
    (2, 1, 1, '2022-01-31', 10, 8),
    (3, 1, 1, '2022-01-31', 100, 9),
    (4, 1, 2, NULL, 1, 10),
    (5, 1, 1, '2022-02-31', 1, 15),
    (6, 1, 1, '2022-02-31', 10, 12),
    (7, 1, 1, '2022-02-31', 100, 13),
    (8, 1, 1, NULL, 1, 17),
    (9, 1, 1, NULL, 10, 14),
    (10, 1, 1, NULL, 100, 16),
    (11, 2, 1, NULL, 1, 99),
    (12, 1, 2, '2022-02-31', 10, 80)
;

SELECT 
   o.id,
   o.supplier_id,
   o.date,
   ol.article_id,
   ol.order_quantity,
   ol.order_price,
   p.list_price
FROM 
   `order` o JOIN order_lineitem ol on ol.order_id = o.id
   LEFT OUTER JOIN prices p on 
           p.article_id = ol.article_id
       AND p.supplier_id = o.supplier_id
       AND p.minimum_order_quantity <= ol.order_quantity
       AND IFNULL(p.valid_until, DATE('2099-12-31')) >= o.date
       /* here comes the fun part that doesn't work (reliably) */
       /* NOTE: I am purposesly commenting out the ORDER BY clause here, because
          (a) it would have to go after GROUP BY - requiring a nested table which I would like to prevent AND, more importantly,
          (b) limiting the numer of rows returned to 1 by GROUPing with an incomplete set of columns on a sorted table may return non-deterministic results as per the MySQL documentation.
          see also https://stackoverflow.com/a/14770936/9818188 explaining the issue with GROUP BY in this context 
       #
       # ORDER BY 
       #   IFNULL(p.valid_until, DATE('2099-12-31')) asc,
       #   p.minimum_order_quantity desc
       */
       GROUP BY o.id, ol.id, p.article_id
       /* ... trying to get only THAT price from the prices table that applies for the 
          (a) the given article
          (b) from the given supplier
          (c) that was valid at the time of purchase (i.e. has the smallest "valid_until" date that is greater than the purchase date)
          (d) when ordering the given quantity (prices can also increase with higher quantities, so it has to be the price with the largest minimum_order_quantity that is smaller than the ordered quantity)
       */

If you are interrestd in the highest listprice, you would do it like the.如果您对最高标价感兴趣,您会喜欢的。

If you need also other columns from theprices table, you need to SQL select only rows with max value on a column如果您还需要价格表中的其他列,则需要SQL 仅选择列上具有最大值的行

as you have to join the sub querys for all articles因为您必须加入所有文章的子查询

SELECT 
   o.id,
   o.date,
   ol.article_id,
   ol.order_quantity,
   ol.order_price,
     (SELECT  `list_price`  FROM prices p WHERE 
              p.article_id = ol.article_id
       AND p.supplier_id = o.supplier_id
       AND p.minimum_order_quantity <= ol.order_quantity
       AND IFNULL(p.valid_until, DATE('2099-12-31')) >= o.date
ORDER BY `list_price` DESC
LIMIT 1
   ) list_price
FROM 
   `order` o JOIN order_lineitem ol on ol.order_id = o.id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM