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

pxyaymoc  于 2023-03-17  发布在  Mysql
关注(0)|答案(2)|浏览(81)

我有这样一张table:
| 计数|产品|
| - ------|- ------|
| 一百|苹果、橙子、芒果|
| 五十|苹果葡萄鳄梨|
| 二十个|橙子、苹果、鳄梨|
如何选择像这样获取每个产品的计数?
| 计数|产品|
| - ------|- ------|
| 一百七十|苹果|
| 一百二十|橙子|
| 一百|芒果|
| 七十|鳄梨|
| 五十|葡萄|

0yycz8jy

0yycz8jy1#

假设Product是一个字符列,并且其中存储了一个“逗号分隔列表”,那么实现指定结果的SQL将非常麻烦。
SQL并不是为将逗号分隔列表中的字符串拆分成单独的行而设计的,这种表设计违背了关系数据库设计的最佳实践原则。
我强烈推荐Bill Karwin的优秀著作“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类型的操作来进行匹配,这会使查询更简单一些。

ljsrvy3e

ljsrvy3e2#

你真的真的需要把table修好。也许这就是你在这里努力实现的目标。
我个人会:

  • 将表中的所有产品名称放入文本文件
  • 用换行符替换逗号
  • 修剪多余空白
  • 全部小写
  • 删除重复项(甚至可以按字母顺序排列)
  • 导入到数据库新表中(产品)

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;

现在我有了所有可能的产品名称(apple apples avocado grapes mango橙子),可以开始重建源表了:

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替换为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的replace是区分大小写的,所以我们从

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

相关问题