2010-07-01 89 views
12

我需要滿足以下條件,任何人都可以請幫我做。多個等級

Rank Cust_Type Cust_Name Revenue 
1  Top   A   10000 
2  Top   B   9000 
3  Top   C   8000 
1  Bottom  X   5000 
2  Bottom  Y   6000 
3  Bottom  Z   7000 

我需要獨立的排名,頂部和底部Cust_Type和所有這些都在MySQL中。

+2

您是否在問如何創建此表? 如何查詢此表的某些內容? 如何查詢另一個表以獲得像這樣的結果? – grossvogel 2010-07-01 23:45:48

+0

請根據您收到的答案使用評論功能進行說明。如果某些內容不適合評論,則應該將其編輯到您的問題中(請參閱編輯鏈接) – 2011-09-21 20:41:01

回答

20

這是一個有點棘手。你可能想使用變量,如在下面的例子:

SELECT ( 
      CASE cust_type 
      WHEN @curType 
      THEN @curRow := @curRow + 1 
      ELSE @curRow := 1 AND @curType := cust_type END 
     ) + 1 AS rank, 
      cust_type, 
      cust_name, 
      revenue 
FROM  sales, 
      (SELECT @curRow := 0, @curType := '') r 
ORDER BY cust_type DESC, revenue DESC; 

(SELECT @curRow := 0, @curType := '') r部分允許變量初始化,而不需要單獨SET命令。

測試用例:

CREATE TABLE sales (cust_type varchar(10), cust_name varchar(10), revenue int); 

INSERT INTO sales VALUES ('Top', 'A', 10000); 
INSERT INTO sales VALUES ('Top', 'B', 9000); 
INSERT INTO sales VALUES ('Top', 'C', 8000); 
INSERT INTO sales VALUES ('Bottom', 'X', 5000); 
INSERT INTO sales VALUES ('Bottom', 'Y', 6000); 
INSERT INTO sales VALUES ('Bottom', 'Z', 7000); 

結果:

+------+-----------+-----------+---------+ 
| rank | cust_type | cust_name | revenue | 
+------+-----------+-----------+---------+ 
| 1 | Top  | A   | 10000 | 
| 2 | Top  | B   | 9000 | 
| 3 | Top  | C   | 8000 | 
| 1 | Bottom | Z   | 7000 | 
| 2 | Bottom | Y   | 6000 | 
| 3 | Bottom | X   | 5000 | 
+------+-----------+-----------+---------+ 
6 rows in set (0.00 sec) 

另一測試情況:

CREATE TABLE sales (cust_type varchar(10), cust_name varchar(10), revenue int); 

INSERT INTO sales VALUES ('Type X', 'A', 7000); 
INSERT INTO sales VALUES ('Type X', 'B', 8000); 
INSERT INTO sales VALUES ('Type Y', 'C', 5000); 
INSERT INTO sales VALUES ('Type Y', 'D', 6000); 
INSERT INTO sales VALUES ('Type Y', 'E', 4000); 
INSERT INTO sales VALUES ('Type Z', 'F', 4000); 
INSERT INTO sales VALUES ('Type Z', 'G', 3000); 

結果:

+------+-----------+-----------+---------+ 
| rank | cust_type | cust_name | revenue | 
+------+-----------+-----------+---------+ 
| 1 | Type Z | F   | 4000 | 
| 2 | Type Z | G   | 3000 | 
| 1 | Type Y | D   | 6000 | 
| 2 | Type Y | C   | 5000 | 
| 3 | Type Y | E   | 4000 | 
| 1 | Type X | B   | 8000 | 
| 2 | Type X | A   | 7000 | 
+------+-----------+-----------+---------+ 
7 rows in set (0.00 sec) 

升序排列,而不是下降可以明顯訂購cust_type。我用降只是在原有的測試案例Bottom之前有Top

+2

非常好的解決方案。我希望MySQL團隊能夠提供窗口和分析功能來避免這些變通方法。 – Shiva 2012-02-01 03:56:41

+0

我不明白爲什麼上述不起作用,當我使用\ @curRow:= 0 AND \ @curType:= cust_type而不是這裏使用的:= 1。 – mathieu 2012-06-19 08:14:03

+0

我剛剛嘗試使用此解決方案,並注意到一些奇怪的事情。我只是想看看每個組的最高值,所以我在查詢結尾添加了'rank = 1'。它顯示了正確的行,但排列的列都是2.如果我只是使用沒有HAVING子句的查詢,它可以正常工作(從rank = 1開始每個組)。萬一它很重要,而不是使用一個表我使用的是一個視圖,ORDER BY條件是在視圖定義。 – Barmar 2012-10-03 20:13:12

1

什麼是不完全清楚的是該項目應如何進行排名(我假定按收入),還是你只是拉一定數量值(例如頂部3和底部3),所以我假設你想要的所有值。鑑於這些假設,

Select Cust_Name, Cust_Type 
    , (Select Count(*) 
     From Table As T1 
     Where T1.Revenue > T.Revenue) + 1 As Rank 
From Table As T 
Where Cust_Type = 'Top' 
Union All 
Select Cust_Name, Cust_Type 
    , (Select Count(*) 
     From Table As T1 
     Where T1.Revenue < T.Revenue) + 1 As Rank 
From Table As T 
Where Cust_Type = 'Bottom' 

如果你想這樣做在一個單一的非工會查詢,你可以這樣做:

Select Cust_Name, Cust_Type 
    , Case Z.Cust_Type 
     When 'Top' Then Z.TopRank 
     Else Z.BottomRank 
     End As Rank 
From (
     Select Cust_Name, Cust_Type 
      , (Select Count(*) 
       From Table As T1 
       Where T1.Revenue > T.Revenue) + 1 As TopRank 
      , (Select Count(*) 
       From Table As T1 
       Where T1.Revenue < T.Revenue) + 1 As BottomRank 
     From Table As T 
     ) As Z 
3

我發現與解決的問題使用CASE@curRow@curType 。這取決於MySQL用來處理查詢的執行計劃。例如,如果向查詢添加連接,它就會顯示出來。那麼不能保證排名會被正確計算。

使答案略有變化:

CREATE TABLE sales (cust_type_id int, cust_name varchar(10), revenue int); 
CREATE TABLE cust_type (cust_type_id int, type_name varchar(10)); 

INSERT INTO cust_type VALUES (1, 'Bottom'); 
INSERT INTO cust_type VALUES (2, 'Top'); 

INSERT INTO sales VALUES (2, 'A', 10000); 
INSERT INTO sales VALUES (2, 'B', 9000); 
INSERT INTO sales VALUES (2, 'C', 8000); 
INSERT INTO sales VALUES (1, 'X', 5000); 
INSERT INTO sales VALUES (1, 'Y', 6000); 
INSERT INTO sales VALUES (1, 'Z', 7000); 

如果我僅查詢sales表我得到正確的順序排名,但如果我加入到cust_type表中的等級值不再正確

SELECT ( 
      CASE s.cust_type_id 
      WHEN @curType 
      THEN @curRow := @curRow + 1 
      ELSE @curRow := 1 AND @curType := s.cust_type_id END 
     ) AS rank, 
      t.type_name, 
      s.cust_name, 
      s.revenue 
FROM  sales s, 
      cust_type t, 
      (SELECT @curRow := 0, @curType := 0) r 
WHERE s.cust_type_id = t.cust_type_id 
ORDER BY t.type_name DESC, s.revenue DESC; 

結果:

+------+-----------+-----------+---------+ 
| rank | type_name | cust_name | revenue | 
+------+-----------+-----------+---------+ 
| 1 | Top  | A   | 10000 | 
| 2 | Top  | B   | 9000 | 
| 3 | Top  | C   | 8000 | 
| 3 | Bottom | Z   | 7000 | 
| 2 | Bottom | Y   | 6000 | 
| 1 | Bottom | X   | 5000 | 
+------+-----------+-----------+---------+ 

的MySQL爲r unning初始查詢到一個臨時表,然後將ORDER BY被秩後對臨時表執行已經計算的。

2

這與托馬斯的答案,但稍微簡單:

SELECT (SELECT COUNT(Cust_Type) FROM sales 
      WHERE Cust_Type = S.Cust_Type AND Revenue >= S.Revenue) AS Rank, 
     Cust_Type, 
     Cust_Name, 
     Revenue 
    FROM sales AS S 
    ORDER BY Cust_Type DESC, Rank; 

我不知道如何表現比較給丹尼爾的解決方案,尤其是在非常大的數據集,或者如果你有使用複雜的連接。

0

這對我來說通過保持銷售收入和訂單分開排列。

SELECT 
     (Select count(s1.revenue)+1 from sales s1 where s.cust_type_id = s1.cust_type_id and s1.revenue > s.revenue) 
      As rank, 
t.type_name, 
      s.cust_name, 
      s.revenue 
FROM  sales s LEFT JOIN 
      cust_type t USING(cust_type_id) 
      Group by t.type_name,s.cust_name,s.revenue DESC order by s.revenue DESC;