2016-12-15 55 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