从一个表中拆分每个产品的计数

时间:2016-12-15 23:52:35

标签: mysql

我有一张这样的表:

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 

2 个答案:

答案 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