2012-04-29 49 views
3

我有這樣的桌子;如何只計算前5個項目,然後將其餘項目分組在其他項目下?

+----+---------+-------------+ 
| id | user_id | screenWidth | 
+----+---------+-------------+ 
| 1 |  1 |  1366 | 
| 2 |  1 |  1366 | 
| 3 |  1 |  1366 | 
| 4 |  1 |  1366 | 
| 5 |  2 |  1920 | 
| 6 |  2 |  1920 | 
| 7 |  3 |  1920 | 
| 8 |  4 |  1280 | 
| 9 |  5 |  1280 | 
| 10 |  6 |  1280 | 
| 11 |  7 |  1890 | 
| ...| ... |  ...  | 
| ...| ... |  ...  | 
| ...| ... |  ...  | 
| 100|  6 |  1910 | 
+----+---------+-------------+ 

哪裏有很多screenWidths,但其中90%等於5個值之一。

使用類似的查詢:

SELECT  screenwidth 
     , COUNT(DISTINCT user_id) AS screenwidthcount 
FROM  screenwidth 
GROUP BY screenwidth 
ORDER BY screenwidthcount; 

(感謝來自How do I count only the first occurrence of a value?

我得到的次屏幕寬度已發生數一個不錯的計數,每個用戶只有一次計數。

有沒有一種方法來計算最流行的screenWidths,然後收集所有其他類別稱爲「其他」 - 也就是說,而不是上面的查詢返回的行加載,它返回6,前5是當前返回的前5位,第6位是其他值與其他值的總和?

+0

你有沒有考慮過使用MySql的'RANK'功能? – Marc

+1

更正:也許在MySql中沒有'RANK'函數。 – Marc

回答

3

這是一種方法。以下腳本是基於對此問題的回答創建的Rank function in MySQL

該查詢爲所有計算機的不同計數的行分配排名。我在CASE表達式中分配了值。這表示該腳本將顯示前兩個屏幕寬度,其餘的將被分成其他。您需要根據您的要求更改值。我已經硬編碼值99999組合所有其他行。

可能有更好的方法來做到這一點,但這是我可以使其工作的方式之一。

Click here to view the demo in SQL Fiddle.

腳本

CREATE TABLE screenwidth 
(
    id INT NOT NULL 
    , user_id INT NOT NULL 
    , screenwidth INT NOT NULL 
); 

INSERT INTO screenwidth (id, user_id, screenwidth) VALUES 
    (1, 1, 1366), 
    (2, 2, 1366), 
    (3, 2, 1366), 
    (4, 2, 1366), 
    (5, 3, 1366), 
    (6, 1, 1920), 
    (7, 2, 1920), 
    (8, 1, 1440), 
    (9, 2, 1440), 
    (10, 3, 1440), 
    (11, 4, 1440), 
    (12, 1, 1280), 
    (13, 1, 1024), 
    (14, 2, 1024), 
    (15, 3, 1024), 
    (16, 3, 1024), 
    (17, 3, 1024), 
    (18, 1, 1366); 

SELECT screenwidth 
    , SUM(screenwidthcount) AS screenwidth_count 
FROM 
(
    SELECT  CASE  
        WHEN @curRank < 2 THEN screenwidth 
        ELSE 'Other' 
       END AS screenwidth 
      , screenwidthcount 
      , @curRank := 
       ( CASE 
         WHEN @curRank < 2 THEN @curRank + 1 
         ELSE 99999 
        END 
       ) AS rank 
    FROM 
    (
     SELECT  screenwidth 
       , COUNT(DISTINCT user_id) AS screenwidthcount 
     FROM  screenwidth 
     GROUP BY screenwidth 
     ORDER BY screenwidthcount DESC 
    ) T1 
       , (SELECT @curRank := 0) r 
) T2 
GROUP BY screenwidth 
ORDER BY rank; 

輸出

SCREENWIDTH SCREENWIDTH_COUNT 
----------- ----------------- 
1440    4 
1024    3 
Other    6 
0

是,與ubiuquitous case語句:我沒有MySQL,但是這一點,或這樣的事情,應該工作...

A.內心的選擇產生screnwidth的結果集,以及不同的計數擁有該屏幕寬度的用戶...(這有效地爲每個用戶統計每個屏幕寬度一次)。結果集僅限於五個或更多用戶使用的屏幕寬度。

B.然後外層查詢將完整的表格加入到該結果集中,將它們分組在一個表達式上並對「Cnt」進行求和,以表示使用每個屏幕寬度的用戶數量。

Select case When Z.Cnt < 5 Then screnwidth, else 0 end 
     Sum(Z.Cnt) screenwidthcount, 
    From screenwidth A 
     Left Join (Select screenwidth, Count(Distinct User_ID) Cnt 
       From screenwidth 
       Group By screenwidth 
       Having count(*) > 4) Z 
     On Z.screeenwidth = A.screeenwidth   
    Group By case When Z.Cnt < 5 Then screnwidth, else 0 end 

C.如果MySQL有一個像SQL Server的功能Str()功能,你可以用它來CASE表達式轉換爲字符串,那麼其他後insteaed的0,你可以使用「其他」

Select case When Z.Cnt < 5 Then Str(screnwidth, 6,0) else 'other' end 
     Sum(Z.Cnt) screenwidthcount, 
    From screenwidth A 
     Left Join (Select screenwidth, Count(Distinct User_ID) Cnt 
       From screenwidth 
       Group By screenwidth 
       Having count(*) > 4) Z 
     On Z.screeenwidth = A.screeenwidth   
    Group By case When Z.Cnt < 5 Then Str(screnwidth, 6,0) else 'other' end 
+0

OP沒有要求5個或更多用戶的屏幕寬度,而是5個最流行的屏幕寬度。 – MatBailie

+0

除了他說「每個用戶只計算一次」,這使得它有效地計算用戶。 –

+0

當然,使用'COUNT(DISTINCT user_id)'來排列屏幕寬度。但是,你需要一個「LIMIT 5」類型的答案;如果每個屏幕寬度都有5個以上的用戶,那麼您將返回每個屏幕寬度,因爲OP希望只有5個最高排名。 – MatBailie

1

試試這個:

select 

    case when rank <= 5 then rank else 'Other' end as screenwidth, 

    sum(screenwidthcount) as screenwidthcount, 

    least(rank,6) as LimitRank 

from 
(
    SELECT 
    *, (@r := @r + 1) as rank 
    FROM 
    (
    SELECT  screenwidth 
      , COUNT(DISTINCT user_id) AS screenwidthcount 

    FROM  tbl 

    GROUP BY screenwidth 
    ORDER BY screenwidthcount desc, screenwidth desc 
) AS X 
    cross join (select @r := 0 as init) rx 
) as y 

group by LimitRank 

數據樣本:

CREATE TABLE tbl 
    (id int, user_id int, screenWidth int); 

INSERT INTO tbl 
    (id, user_id, screenWidth) 
VALUES 
    (1, 1, 1366), 
    (2, 1, 1366), 
    (3, 1, 1366), 
    (4, 1, 1366), 
    (5, 2, 1920), 
    (6, 2, 1920), 
    (7, 3, 1920), 
    (8, 4, 1280), 
    (9, 5, 1280), 
    (10, 6, 1280), 
    (11, 7, 1890), 
    (12, 9, 1890), 
    (13, 9, 1890), 
    (13, 9, 1024), 
    (13, 9, 800), 
    (100, 6, 1910); 

輸出:

SCREENWIDTH SCREENWIDTHCOUNT LIMITRANK 
1280  3     1 
1920  2     2 
1890  2     3 
1910  1     4 
1366  1     5 
Other  2     6 

現場測試:http://www.sqlfiddle.com/#!2/c0e94/33


這裏是不封頂的結果:http://www.sqlfiddle.com/#!2/c0e94/31

SCREENWIDTH SCREENWIDTHCOUNT 
1280  3 
1920  2 
1890  2 
1910  1 
1366  1 
1024  1 
800   1 
相關問題