2014-04-04 64 views
0

我有一個MySQL表所示波紋管的多次出現,MySQL的計數復條目

id   reasonCode 
------  ------------------ 
    1   0, 1 
    2   0 
    3   1, 2, 3 
    4   2 
    5   1, 0 

而且我想輸出

reasonCode   occurrences 

    0      3 
    1      3 
    2      2 
    3      1 

我試圖「分組依據」,但它給出了這樣的事情。

reasonCode   occurrences 

    0, 1     1 
    0      1 
    1, 2, 3    1 
    2      1 
    1, 0     1 

如果有人有任何想法如何做到這一點,將不勝感激。

+4

RDBMS是不恰當的在一個單元中保存多值數據。請規範你的表格結構(之前爲時已晚)。只有一個'reasonCode'應該存儲在一行中(而不是以逗號分隔的值)。你正在嘗試做什麼也許可能,但可能會產生開銷和性能問題。 –

+0

@AzizShaikh,實際上,reasonCode存儲爲varChar(45)數據類型,存儲多個值的原因是可能有多個停止計算機的原因,並且應該以單個條目形式存在。 – ashok

回答

0

如果你有原因代碼表(我想你做的,所以你知道是什麼意思是例如原因代碼1),那麼你可以做這樣的事情: -

SELECT a.id, COUNT(b.id) 
FROM reason_codes a 
LEFT OUTER JOIN id_reason_code b 
ON FIND_IN_SET(a.id, b.reasonCode) 
GROUP BY a.id 

然而,這樣做的一個問題是在逗號後面有空格。逗號分隔的字段在最好的時候是個問題(如果需要,可以更好地將它們拆分成多行) - 但逗號後面的空格會給出問題(請注意,刪除這些空格也會讓@Vignesh Kumar的解決方案更簡單一些)。

爲了避開這個你可以這樣做: -

SELECT a.id, COUNT(b.id) 
FROM reason_codes a 
LEFT OUTER JOIN id_reason_code b 
ON FIND_IN_SET(a.id, REPLACE(b.reasonCode, ' ', '')) 
GROUP BY a.id 

編輯 - 解釋

這僅僅是一個LEFT OUTER JOIN。這將從第一個表(即原因代碼)獲取每一行,並將其與第二個表上匹配的任何行進行匹配(即,ie_reason_code - 不確定上面顯示的是什麼表)。如果第二張表上沒有匹配的行,那麼第一張表中的行仍然會被帶回,但第二張表中的列中將返回NULL。在這種情況下,連接基於FIND_IN_SET完成。這將查找逗號分隔值列表中的第一個參數,如果找到則返回該位置(因此如果發現它的計算結果爲true)。

COUNT/GROUP BY然後計算每個a.id的b.id值的數量並顯示該數量。

第二個查詢做的是一樣的,但它在檢查值之前從逗號分隔列表中刪除任何空格(當您有空格以及逗號分隔值時需要)。

如果你有下列表格: -

reason_codes table 
id reason 
0 Reason A 
1 Reason B 
2 Reason C 
3 Reason D 
4 Reason E 

id_reason_code table 
id   reasonCode 
1   0,1 
2   0 
3   1,2,3 
4   2 
5   1,0 

那麼下面的SQL(移除COUNT/GROUP BY): -

SELECT a.id, b.id 
FROM reason_codes a 
LEFT OUTER JOIN id_reason_code b 
ON FIND_IN_SET(a.id, b.reasonCode) 

會給像下面這樣: -

a.id b.id 
0  1 
0  2 
0  5 
1  1 
1  3 
1  5 
2  3 
2  4 
3  3 
4  NULL 

運行: -

SELECT a.id, COUNT(b.id) 
FROM reason_codes a 
LEFT OUTER JOIN id_reason_code b 
ON FIND_IN_SET(a.id, b.reasonCode) 
GROUP BY a.id 

的COUNT/GROUP BY是給一行a.id的每個值,然後將該值的b.id的用於a.id:-

a.id count(b.id) 
0  3 
1  3 
2  2 
3  1 
4  0 
該數值的計數(非空)

您還可以帶回的實際原因,而不是代碼,如果你想: -

SELECT a.id, a.reason, COUNT(b.id) 
FROM reason_codes a 
LEFT OUTER JOIN id_reason_code b 
ON FIND_IN_SET(a.id, b.reasonCode) 
GROUP BY a.id, a.reason 

,並提供: -

a.id a.reason count(b.id) 
0  Reason A 3 
1  Reason B 3 
2  Reason C 2 
3  Reason D 1 
4  Reason E 0 
+0

謝謝,請你解釋一下查詢嗎? – ashok

+0

添加了解釋 – Kickstart

+0

謝謝,我會試試看。 – ashok

1

嘗試此查詢

SELECT Reason,COUNT(Reason) FROM 
(
SELECT 
    id, 
    SUBSTRING_INDEX(SUBSTRING_INDEX(reasoncode, ',', n.digit+1), ',', -1) Reason 
FROM 
    table1 
    INNER JOIN 
    (SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) n 
    ON LENGTH(REPLACE(reasoncode, ',' , '')) <= LENGTH(reasoncode)-n.digit 
ORDER BY 
    id, 
    n.digit 
) T 

Group By Reason; 

SQL FIDDLE

輸出爲:

REASON OCCURANCES 
0   3 
1   3 
2   2 
3   1 
+0

感謝您的重播。實際上,原因代碼的數量會發生變化。用戶可以隨時添加/刪除原因代碼。 – ashok

+0

你可以說,與示例數據 –

+0

我的意思是有一個配置表在屏幕上(這也是在MySQL數據庫),用戶可以在其中輸入原因和reasonCodes。例如。對於原因代碼「0」,原因是「維護」,對於原因代碼「1」,原因是「材料短缺」,並且可能在其他日子將他交換該原因代碼。 – ashok

1

...的原因代碼NUM要改變。用戶可以添加/每當他想要刪除的原因代碼...

如果什麼數字會在那裏爲原因代碼部分是不知道,那麼你最好生成動態查詢。您可以通過存儲過程來完成此操作。

步驟遵循

  1. 抓取每個原因代碼串中一個變量。
  2. 拆分它找到每個原因代碼。
  3. 生成select與發現的代碼和它的1
  4. Union all計數,如果產生了一些所有這樣的語句。
  5. 循環直到每個字符串中不再存在代碼。
  6. 重複,直到處理所有行
  7. 現在,通過 原因碼在生成的結果集組上運行聚合函數。
  8. 您已收到結果。示例代碼段的

部分:

-- ... 

set @sql_query := 'select reason_code, sum(rc_count) as rc_count from (' ; 
set @sql_query := 
     concat(@sql_query, 
       '\n (select null as reason_code, 0 as rc_count)'); 

-- ... 

splitting_reason_codes: loop 
    set comma_position = locate(',', reason_code_string); 
    if comma_position then 
    set rc := substring(reason_code_string, 1, comma_position-1); 
    set reason_code_string := 
      substring(reason_code_string, comma_position+1); 
    else 
    set rc := reason_code_string; 
    end if; 

    if length(rc) > 0 then 
    set @sql_query := 
      concat(@sql_query, 
        '\n union all (select ', rc, ', 1)'); 
    end if; 

    if ! comma_position then 
    leave splitting_reason_codes; 
    end if; 
end loop splitting_reason_codes; 

-- ... 

set @sql_query := concat(@sql_query, '\n) unique_reason_codes'); 
set @sql_query := concat(@sql_query, '\nwhere reason_code is not null'); 
set @sql_query := concat(@sql_query, '\ngroup by reason_code'); 
set @sql_query := concat(@sql_query, '\norder by reason_code'); 

prepare stmt from @sql_query; 
execute stmt; 

演示 @SQL Fiddle