MySQL 设置第一列和第二列的排名
MySQL SET rank over First Column and Second Column
我正在尝试按第一列和第二列创建查询设置排名列。就像 Rank over Partition 不存在 MySQL
例如,
来自
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | |
| 2 | a | 9 | |
| 3 | b | 10 | |
| 4 | b | 7 | |
| 5 | a | 1 | |
| 6 | b | 1 | |
+----+-------+--------+------+
到
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
排名没有继续。当到达'First'列的'a'的最后一个值时,它又从1开始。
而且必须是 SET 而不是 SELECT。
我不介意使用 SELECT,但我的意思是我不是要从数据库中检索数据,而是要设置值。
提前为队友干杯。
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,first CHAR(1) NOT NULL
,second INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'a',10),
(2,'a',9),
(3,'b',10),
(4,'b',7),
(5,'a',1),
(6,'b',1);
SELECT id
, first
, second
, rank
FROM
( SELECT x.*
, CASE WHEN @prev = first THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=first
FROM my_table x
, (SELECT @prev:=null,@i:=0) vars
ORDER
BY first
, second
, id
) a
ORDER
BY id;
+----+-------+--------+------+
| id | first | second | rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
6 rows in set (0.00 sec)
一种方法是相关子查询。对于 rank()
你可以这样做:
select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as rank
from t;
排名很难用变量处理(dense_rank()
和 row_number()
更简单)。
编辑:
这很容易变成 update
:
update t join
(select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as new_rank
from t
) tt
on t.id = tt.id
set t.rank = tt.new_rank;
提出了我正在寻找的解决方案。
我不确定这些查询是否完全安全,但到目前为止没有危害。
SET @rank = 0, @First = ''
UPDATE 'Table' SET
rank = IF(@First = First, @rank:= @rank +1, @rank := 1 AND @First := First)
ORDER BY First ASC, Second;
我正在尝试按第一列和第二列创建查询设置排名列。就像 Rank over Partition 不存在 MySQL
例如,
来自
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | |
| 2 | a | 9 | |
| 3 | b | 10 | |
| 4 | b | 7 | |
| 5 | a | 1 | |
| 6 | b | 1 | |
+----+-------+--------+------+
到
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
排名没有继续。当到达'First'列的'a'的最后一个值时,它又从1开始。
而且必须是 SET 而不是 SELECT。 我不介意使用 SELECT,但我的意思是我不是要从数据库中检索数据,而是要设置值。
提前为队友干杯。
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,first CHAR(1) NOT NULL
,second INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'a',10),
(2,'a',9),
(3,'b',10),
(4,'b',7),
(5,'a',1),
(6,'b',1);
SELECT id
, first
, second
, rank
FROM
( SELECT x.*
, CASE WHEN @prev = first THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=first
FROM my_table x
, (SELECT @prev:=null,@i:=0) vars
ORDER
BY first
, second
, id
) a
ORDER
BY id;
+----+-------+--------+------+
| id | first | second | rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
6 rows in set (0.00 sec)
一种方法是相关子查询。对于 rank()
你可以这样做:
select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as rank
from t;
排名很难用变量处理(dense_rank()
和 row_number()
更简单)。
编辑:
这很容易变成 update
:
update t join
(select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as new_rank
from t
) tt
on t.id = tt.id
set t.rank = tt.new_rank;
提出了我正在寻找的解决方案。 我不确定这些查询是否完全安全,但到目前为止没有危害。
SET @rank = 0, @First = ''
UPDATE 'Table' SET
rank = IF(@First = First, @rank:= @rank +1, @rank := 1 AND @First := First)
ORDER BY First ASC, Second;