views:

58

answers:

3

Hi, I need the following, Can anyone please help me do it.

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

I need separate ranks for Top and Bottom Cust_Type and all this is in MySQL.

+2  A: 

This is a bit tricky. You may want to use variables, such as in the following example:

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;

The (SELECT @curRow := 0, @curType := '') r part allows the variable initialization without requiring a separate SET command.

Test case:

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);

Result:

+------+-----------+-----------+---------+
| 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)

Another test case:

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);

Result:

+------+-----------+-----------+---------+
| 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)

You can obviously order the cust_type in ascending order instead of descending. I used descending just to have Top before Bottom in the original test case.

Daniel Vassallo
A: 

Sorry for not being specific. I need to query few tables to get this result using MySQL. Will your first solution work for my requirement?

Thanks.

Nikhil
@Nikhil: You may want to delete this answer and update the question instead... Apart from that, do you think you can give an example of the query you are using?
Daniel Vassallo
A: 

What is not exactly clear is how the items should be ranked (I assumed by Revenue) or whether you are only pulling a certain number of values (e.g. the top 3 and the bottom 3) so I assumed you wanted all values. Given those assumptions,

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'

If you were trying to do this in a single non-union query you could do:

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
Thomas