在 mysql 中获得 GROUP BY 的最高计算分数

Getting highest calculated score of GROUP BY in mysql

我正在尝试根据客户 and/or 他的客户群检索每个数量的产品的最合适价格。为此,我使用了一个基于权重的系统:匹配的客户组比匹配的客户更重要,所以如果两行发生冲突,我们应该得到与客户组 id 对应的行。

这是一个例子:

Customer n°1 is part of Customer group n°2
Product prices:
 A - 90€ for customer n°1 (when buying at least 2 of the same product)
 B - 80€ for customer group n°2 (when buying at least 2 of the same product)
So the price shown to the customer n°1 should be 80€

他是我的查询:

SELECT 
    MAX(IF(t.customer_id = 1, 10, 0) + IF(t.customer_group_id = 1, 100, 0)) as score, 
    t.*
FROM tierprice t
WHERE t.product_variant_id = 110 
    AND (t.customer_id = 1 OR t.customer_id IS NULL) 
    AND (t.customer_group_id = 1 OR t.customer_group_id IS NULL)
GROUP BY t.product_variant_id, t.qty

我遇到的问题是结果行中显示了正确的分数(此处:100),但给定分数的行不正确。估计跟SELECT和GROUP BY里面的MAX有关系,但是不知道怎么给行赋分,然后取最高的

这是一个 fiddle :

CREATE TABLE `tierprice` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_variant_id` int(11) DEFAULT NULL,
  `customer_group_id` int(11) DEFAULT NULL,
  `price` int(11) NOT NULL,
  `qty` int(11) NOT NULL,
  `customer_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `no_duplicate_prices` (`qty`,`product_variant_id`,`customer_group_id`),
  KEY `IDX_BA5254F8A80EF684` (`product_variant_id`),
  KEY `IDX_BA5254F8D2919A68` (`customer_group_id`),
  KEY `IDX_BA5254F89395C3F3` (`customer_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `tierprice` (`id`, `product_variant_id`, `customer_group_id`, `price`, `qty`, `customer_id`)
VALUES
    (1, 110, NULL, 8000, 2, 1),
    (2, 110, 1, 7000, 2, NULL),
    (3, 110, 1, 6000, 5, NULL),
    (4, 110, NULL, 5000, 5, 1),
    (5, 111, 1, 8000, 2, NULL),
    (6, 111, NULL, 6000, 2, 1),
    (7, 111, 1, 7000, 6, NULL),
    (8, 111, NULL, 5000, 6, 1);

http://sqlfiddle.com/#!9/7bc0d9/2

结果中应该出现的价格id应该是ID 2和ID 3。

感谢您的帮助。

您的查询可以 return 的唯一有效列是您在 GROUP BY 子句中使用的 product_variant_idqty 和聚合列 score.
因为 t.* 你得到了 table 的所有列,但是 选择的值是不确定的 ,对于其他列,正如 [=17= 中解释的那样].
您可以做的是像这样将您的查询加入 table:

SELECT t.*
FROM tierprice t
INNER JOIN (
  SELECT product_variant_id, qty, 
         MAX(IF(customer_id = 1, 10, 0) + IF(customer_group_id = 1, 100, 0)) as score
  FROM tierprice 
  WHERE product_variant_id = 110 
    AND (customer_id = 1 OR customer_id IS NULL) 
    AND (customer_group_id = 1 OR customer_group_id IS NULL)
  GROUP BY product_variant_id, qty
) g ON g.product_variant_id = t.product_variant_id 
   AND g.qty = t.qty
   AND g.score = IF(t.customer_id = 1, 10, 0) + IF(t.customer_group_id = 1, 100, 0)
WHERE (t.customer_id = 1 OR t.customer_id IS NULL) 
  AND (t.customer_group_id = 1 OR t.customer_group_id IS NULL)

参见demo
结果:

> id | product_variant_id | customer_group_id | price | qty | customer_id
> -: | -----------------: | ----------------: | ----: | --: | ----------:
>  2 |                110 |                 1 |  7000 |   2 |        null
>  3 |                110 |                 1 |  6000 |   5 |        null

从 SQL 标准的角度来看,提供的查询不是有效查询:

SELECT 
    MAX(IF(t.customer_id = 1, 10, 0) + IF(t.customer_group_id = 1, 100, 0)) as score, 
    t.*
FROM tierprice t
WHERE t.product_variant_id = 110 
    AND (t.customer_id = 1 OR t.customer_id IS NULL) 
    AND (t.customer_group_id = 1 OR t.customer_group_id IS NULL)
GROUP BY t.product_variant_id, t.qty;

Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 't.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

相关:


可以使用窗口函数重写(MySQL 8.0及以上):

WITH cte AS (
 SELECT t.*, ROW_NUMBER() OVER(PARTITION BY product_variant_id, qty 
             ORDER BY IF(t.customer_id=1,10,0)+IF(t.customer_group_id=1,100,0) DESC) AS rn
 FROM tierprice t
 WHERE t.product_variant_id = 110 
     AND (t.customer_id = 1 OR t.customer_id IS NULL) 
     AND (t.customer_group_id = 1 OR t.customer_group_id IS NULL)
)
SELECT *
FROM cte
WHERE rn = 1;

db<>fiddle demo