在 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_id
、qty
和聚合列 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;
我正在尝试根据客户 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_id
、qty
和聚合列 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;