我有一张这样的表:
Count Product
100 apple, orange, mango
50 apple, grape, avocado
20 orange, apple, avocado
如何选择每件产品的计数?
Count Product
170 apple
120 orange
100 mango
70 avocado
50 grape
答案 0 :(得分:2)
假设Product
是一个字符列,并且存储了值的“逗号分隔列表”,那么实现指定结果的SQL很麻烦。
SQL不是为了将逗号分隔列表中的字符串拆分为单独的行而设计的。该表设计面向最佳实践关系数据库设计原则。
我强烈推荐Bill Karwin的优秀书籍“SQL Antipatterns:避免数据库编程的陷阱”。第2章“Jaywalking”目前在亚马逊的“内部”功能中可用...
https://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557
然而,回答你问的问题。可以实现指定的结果。这适用于示例案例,但不一定是其他更常见的案例:
SELECT REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE( c.Product
,'Apples','Apple'
),'apple','Apple'
),'orange','Orange'
),'mango','Mango'
),'grapes','Grapes'
),'avocado','Avocado'
) AS `Product`
, SUM(c.Count) AS `Count`
FROM ( SELECT TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(d.Product,',',n.i),',',-1)) AS `Product`
, d.Count
FROM ( SELECT 1 AS i UNION ALL SELECT 2 UNION ALL SELECT 3 ) n
CROSS
JOIN ( -- table of example data
SELECT 100 AS `Count`, 'Apples, orange, mango' AS `Product`
UNION ALL SELECT 50, 'Apples, grapes, avocado'
UNION ALL SELECT 20, 'Orange, apple, avocado'
) d
) c
GROUP
BY REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE( c.Product
,'Apples','Apple'
),'apple','Apple'
),'orange','Orange'
),'mango','Mango'
),'grapes','Grapes'
),'avocado','Avocado'
)
ORDER BY 2 DESC, 1 ASC
返回:
Product Count
------- --------
Apple 170
Orange 120
Mango 100
Avocado 70
Grapes 50
这适用于示例数据,但不适用于其他可能的数据。 (例如,如果逗号分隔的产品列表包含四个项目,或仅包含两个项目。)
如果你有一个单独的表,只返回单个Product
......我们可能会在它和问题中显示的表之间使用JOIN,并使用FIND_IN_SET类型的操作来进行匹配。这会使查询更简单。
答案 1 :(得分:0)
你真的需要修理桌子。也许那就是你想要在这里实现的目标。
我个人会:
CREATE TABLE product
(
id INT(11) UNSIGNED NOT NULL auto_increment,
product VARCHAR(50) NOT NULL DEFAULT '',
PRIMARY KEY (id),
KEY product (product)
)
engine=innodb
DEFAULT charset=utf8;
现在我拥有所有可能的产品名称(苹果苹果鳄梨葡萄芒果橙),并且可以开始重建您的源表:
SELECT p.product,
Sum(src.count)
FROM product p
LEFT JOIN src
ON src.product REGEXP p.product
GROUP BY p.product
;
--
product Sum(src.count)
apple 170
apples 150
avocado 70
grapes 50
mango 100
orange 120
......嗯,用苹果做什么?
一种可能的解决方案是更换所有的苹果'用' apple'
SELECT Concat('UPDATE src SET product = Replace(product, \'', p2.product, '\', \'', p1.product, '\');') AS q
FROM product p1
LEFT JOIN product p2
ON p1.product != p2.product
AND p2.product REGEXP p1.product
WHERE p2.product IS NOT NULL
;
--
q
UPDATE src SET product = Replace(product, 'apples', 'apple');
Mysql的替换区分大小写,所以我们从
开始UPDATE src
SET product = Lower(product);
现在我们可以运行上一个查询的结果:
UPDATE src SET product = Replace(product, 'apples', 'apple');
--
2 rows affected
我们修改过的源表:
SELECT * FROM src
;
-
Count Product
100 apple, orange, mango
50 apple, grapes, avocado
20 orange, apple, avocado
让我们重新开始
下一个查询会让我开心:
CREATE TABLE inventory AS
SELECT p.product,
Sum(src.count) AS count
FROM product p
LEFT JOIN src
ON src.product REGEXP p.product
GROUP BY p.product
;
SELECT * FROM inventory
;
--
product count
apple 170
avocado 70
grapes 50
mango 100
orange 120
瞧