我需要以下内容,任何人都可以帮助我这样做。
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
我需要Top和Bottom Cust_Type的单独排名,所有这些都在MySQL中。
答案 0 :(得分:24)
这有点棘手。您可能希望使用变量,例如以下示例:
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
而不是降序。我在原始测试用例中使用降序只是Top
之前的Bottom
。
答案 1 :(得分: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正在将初始查询运行到临时表中,然后ORDER BY
正在针对临时表执行 已经计算了等级。
答案 2 :(得分:3)
这与托马斯的回答类似,但有点简单:
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;
我不确定性能与Daniel的解决方案相比如何,特别是在非常大的数据集上,或者您必须使用复杂的连接。
答案 3 :(得分: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
答案 4 :(得分:0)
通过保持销售收入排序和订单分开,这对我有用。
getScene()
答案 5 :(得分:0)
对于JOIN表问题,我找到了解决方法。
我创建了一个临时表,这样MySQL可以保持我要排名的值的顺序。
DROP TEMPORARY TABLE IF EXISTS tmp_mytable;
CREATE TEMPORARY TABLE tmp_mytable ENGINE = MEMORY
SELECT mytable.id AS id,
mytable.login AS Login,
cliente.myrank_id AS id_myrank,
mytable.rankvalue AS rankvalue
FROM mytable
INNER JOIN myjoin ON (mytable.id_myjoin = myjoin.id)
ORDER BY 3, 4 DESC;
SELECT id, login, IFNULL(id_myrank, 0) AS id_myrank, rankvalue,
@rank := IF(@prev_born = IFNULL(id_myrank, 0), @rank + 1, 1) AS ranking,
@prev_Born := IFNULL(id_myrank, 0) AS fake_field
FROM tmp_mytable, (select @prev_born := 0, @rank := 0) r
-- HAVING ranking < 20;
* PS:我尝试过创建视图,但是也无法正常工作。