2016-12-15 30 views
0

单位产品计我有这样的一个表:分割从一个表

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

你有一个产品定义表的地方? – shmosel

+2

我推荐Bill Karwin的优秀书的第2章。 (截至本评论,第2章仍然可以在亚马逊的“Look Inside”中看到... https://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557 – spencer7593

+0

假设产品和它的计数是原子数据,我建议将模式更改为“(count,product)”元组,而不是使用它们的(合并?)计数来存储产品列表。 –

回答

2

假设Product是字符列,并且“逗号分隔的列表”的值被存储在它的SQL达到规定的结果是麻烦的。

SQL不是用于将逗号分隔列表中的字符串拆分为单独的行。这个表格设计是面对最佳实践关系数据库设计原则的。

我强烈建议比尔卡尔文的优秀着作“SQL反模式:避免数据库编程的陷阱”。第2章“乱穿马路”,是目前在亚马逊的“往里”功能...

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类型操作来执行该匹配。这会使查询变得更简单一些。

+0

爱那本书! – michelek

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 

...嗯什么与苹果的?

一个可能的解决方案是,以取代所有的“苹果”与“苹果”

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