在mysql中获得GROUP BY的最高计算分数
Posted
技术标签:
【中文标题】在mysql中获得GROUP BY的最高计算分数【英文标题】:Getting highest calculated score of GROUP BY in mysql 【发布时间】:2021-02-21 05:10:21 【问题描述】:我正在尝试根据客户和/或他的客户群检索每种数量的产品最合适的价格。为此,我使用了基于权重的系统:匹配的客户组比匹配的客户更重要,所以如果两行发生冲突,我们应该得到与客户组 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有关系,但是不知道怎么给行赋值,然后取最高的。
这是一个小提琴:
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。
感谢您的帮助。
【问题讨论】:
查看我添加的标签。 您提到了与客户相关联的组。您能否提供显示他们所属的 ID 和 GroupID 的示例客户表?在此示例中,您的所有数据仅指客户 1 和组 1,这与所有数据的真实场景相去甚远。您不希望有一个“硬编码”的解决方案,其中嵌入了特定的 ID。您的团体定价也有 2 和 5 的数量价格断点,也不想固定在那里。 另外,实际订购的数量来自哪里而不是固定的... 订单详情?也显示该来源(包含客户、产品、订购数量的 orderDetail 表)。 【参考方案1】:从 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;
SELECT 列表的表达式 #2 不在 GROUP BY 子句中,包含非聚合列 't.id',它在功能上不依赖于 GROUP BY 子句中的列; 这与 不兼容sql_mode=only_full_group_by
相关:Group by clause in mysql and postgreSQL, why the error in postgreSQL?
可以使用窗口函数重写(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
【讨论】:
【参考方案2】:您的查询可以返回的唯一有效列是product_variant_id
、qty
(您在GROUP BY
子句中使用)和聚合列score
。
由于t.*
,您可以获得表的所有列,但选择的值是不确定的,对于其他列,正如MySQL Handling of GROUP BY 中所解释的那样。
您可以做的是将您的查询加入到表中,如下所示:
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
【讨论】:
以上是关于在mysql中获得GROUP BY的最高计算分数的主要内容,如果未能解决你的问题,请参考以下文章