2013-04-07 110 views
0

我想創建一些關於我的用戶的統計信息。從一個查詢中的一個表中總結不同的值

我想根據他們的年齡段對他們進行分組,並根據他們的性別進行總結。所以最終我得到一個表是這樣的:

age | male | female | total 
    0-18 | 2 |  1 |  3 
18-25 | 3 |  4 |  7 
25-100 | 13 |  25 | 38 
total | 18 |  30 | 48 

(順便說一句,這些都是例子區間。)

了RightNow我做到這一點通過運行該查詢的每一行:

SELECT 
    SUM(IF(gender = 'male', 1,0)) AS `male`, 
    SUM(IF(gender = 'female', 1,0)) AS `female`, 
    COUNT(gender) AS `total` 
FROM `users` 
WHERE 
    `birthday` 
     BETWEEN 
      DATE_SUB(CURDATE(), INTERVAL 25 YEAR) 
     AND 
      DATE_SUB(CURDATE(), INTERVAL 18 YEAR) 

和總結結果由我的PHP腳本創建最後一個總排

我怎麼能結合所有這些查詢來提高性能,也許還創建了通過mysql的最後一條線。

我想使用

的間隔是:

0-18 
18-25 
25-31 
31-36 
36-41 
41-46 
46-51 
51-56 
56-61 
61-100 

編輯: 這裏是一個表的轉儲一些樣​​本數據來測試它http://pastebin.com/ytcuu2ge

SQL Fiddle Schema

+0

你能給樣品記錄嗎? – 2013-04-07 04:38:29

+0

剛剛通過示例轉儲添加了一個指向我的問題的鏈接 – 2013-04-07 04:48:07

+0

您是否也可以在表中添加間隔,例如'interval_id','from'和'to'列? – 2013-04-07 05:03:30

回答

2
SELECT Age, 
     SUM(gender = 'female') Female, 
     SUM(gender = 'male') Male, 
     COUNT(*) TotalPerson 
FROM 
     (
      SELECT CASE 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 0 AND 18 THEN '00-18' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 19 AND 25 THEN '19-25' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 26 AND 31 THEN '26-31' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 32 AND 36 THEN '32-36' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 37 AND 41 THEN '37-41' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 42 AND 46 THEN '42-46' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 47 AND 51 THEN '47-51' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 52 AND 56 THEN '52-56' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 57 AND 61 THEN '57-61' 
         WHEN FLOOR(DATEDIFF(CURDATE(), birthday)/365) BETWEEN 62 AND 100 THEN '62-100' 
        END Age, 
        Gender 
      FROM users 
     ) ageList 
GROUP BY Age 

輸出

╔════════╦════════╦══════╦═════════════╗ 
║ AGE ║ FEMALE ║ MALE ║ TOTALPERSON ║ 
╠════════╬════════╬══════╬═════════════╣ 
║ 00-18 ║  0 ║ 1 ║   1 ║ 
║ 19-25 ║  6 ║ 5 ║   11 ║ 
║ 26-31 ║  22 ║ 4 ║   26 ║ 
║ 32-36 ║  39 ║ 16 ║   56 ║ 
║ 37-41 ║  20 ║ 11 ║   31 ║ 
║ 42-46 ║  31 ║ 6 ║   38 ║ 
║ 47-51 ║  18 ║ 3 ║   21 ║ 
║ 52-56 ║  11 ║ 6 ║   17 ║ 
║ 57-61 ║  10 ║ 6 ║   16 ║ 
║ 62-100 ║  12 ║ 12 ║   24 ║ 
╚════════╩════════╩══════╩═════════════╝ 

輸出使用WITH ROLLUP

╔════════╦════════╦══════╦═════════════╗ 
║ AGE ║ FEMALE ║ MALE ║ TOTALPERSON ║ 
╠════════╬════════╬══════╬═════════════╣ 
║ 00-18 ║  0 ║ 1 ║   1 ║ 
║ 19-25 ║  6 ║ 5 ║   11 ║ 
║ 26-31 ║  22 ║ 4 ║   26 ║ 
║ 32-36 ║  39 ║ 16 ║   56 ║ 
║ 37-41 ║  20 ║ 11 ║   31 ║ 
║ 42-46 ║  31 ║ 6 ║   38 ║ 
║ 47-51 ║  18 ║ 3 ║   21 ║ 
║ 52-56 ║  11 ║ 6 ║   17 ║ 
║ 57-61 ║  10 ║ 6 ║   16 ║ 
║ 62-100 ║  12 ║ 12 ║   24 ║ 
║ TOTAL ║ 169 ║ 70 ║   241 ║ 
╚════════╩════════╩══════╩═════════════╝ 
+1

看來你仍然需要'ROLLUP'來獲得最終**總數**。 – 2013-04-07 05:11:23

+0

@ PM77-1更新。 – 2013-04-07 05:11:48

+0

謝謝你的作品完全如我所願,但我只是發現了一點不愉快的事情。如果其中一個年齡段沒有結​​果,它只會從結果中消失:(如果它沒有用戶的話,甚至會顯示它們會很棒,@Ed Gibbs的解決方案就像這樣工作,但是就像100%在我的大數據庫上比你的解決方案慢。 – 2013-04-07 07:06:59

0

您可以使用UNION ALL如果你有靜態的間隔

SELECT * FROM 
((SELECT 
    '0-18' AS age, 
    SUM(IF(gender = 'male', 1,0)) AS `male`, 
    SUM(IF(gender = 'female', 1,0)) AS `female`, 
    COUNT(gender) AS `total` 
FROM users AS u 
WHERE `birthday` BETWEEN DATE_SUB(CURDATE(), INTERVAL 18 YEAR) 
    AND DATE_SUB(CURDATE(), INTERVAL 0 YEAR)) 
UNION ALL 
(SELECT 
    '18-25' AS age, 
    SUM(IF(gender = 'male', 1,0)) AS `male`, 
    SUM(IF(gender = 'female', 1,0)) AS `female`, 
    COUNT(gender) AS `total` 
FROM users AS u 
WHERE `birthday` BETWEEN DATE_SUB(CURDATE(), INTERVAL 25 YEAR) 
    AND DATE_SUB(CURDATE(), INTERVAL 18 YEAR)) 

    UNION ALL 
(SELECT 
    '25-100' AS age, 
    SUM(IF(gender = 'male', 1,0)) AS `male`, 
    SUM(IF(gender = 'female', 1,0)) AS `female`, 
    COUNT(gender) AS `total` 
FROM users AS u 
WHERE `birthday` BETWEEN DATE_SUB(CURDATE(), INTERVAL 100 YEAR) 
    AND DATE_SUB(CURDATE(), INTERVAL 25 YEAR))) as l 
group by age 

SQL Fiddle Demo

+0

所有應有的尊重它*瘋狂*加上OP想要**提高**性能。 – 2013-04-07 05:16:06

1

你可以做一個非等值連接使用的年齡範圍的「表」:

SELECT 
    AgeRange.Age, 
    SUM(gender = 'male') AS `male`, 
    SUM(gender = 'female') AS `female`, 
    SUM(friends) AS `friends`, 
    COUNT(gender) AS `total` 
FROM `users` 
INNER JOIN (
    SELECT 0 AS Low, 18 AS High, '0-18' AS Age 
    UNION SELECT 18, 25, '18-25' 
    UNION SELECT 25, 31, '25-31' 
    UNION SELECT 31, 36, '31-36' 
    UNION SELECT 36, 41, '36-41' 
    UNION SELECT 41, 46, '41-46' 
    UNION SELECT 46, 51, '46-51' 
    UNION SELECT 51, 56, '51-56' 
    UNION SELECT 56, 61, '56-61' 
    UNION SELECT 61, 100, '61-100') AgeRange 
ON users.birthday BETWEEN 
    DATE_SUB(CURDATE(), INTERVAL AgeRange.High YEAR) AND 
    DATE_SUB(CURDATE(), INTERVAL AgeRange.Low YEAR) 
GROUP BY AgeRange.Age WITH ROLLUP; 

WITH ROLLUP將包括總計行。有一個SQL小提琴here

相關問題