MySQL中的ROW_NUMBER()


281

MySQL中有没有复制SQL Server函数的好方法ROW_NUMBER()

例如:

SELECT 
    col1, col2, 
    ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1

然后,例如,我可以添加一个条件以将限制限制intRow为1,以获得col3(col1, col2)对最高的一行。


9
带有标签greatest-n-per-group以指导您解决类似的问题。
比尔·卡文

1
已删除Sql-Server标签,因为它是组合标签搜索中投票率最高的项目,但与SQL Server并没有真正的关系。
马丁·史密斯

有关简单的mysql行号函数的信息,请查看datamakessense.com/mysql-rownum-row-number-function
AdrianBR 2014年

对于MySQL,只有有效的解决方案在mysql.rjweb.org/doc.php/groupwise_max中讨论。许多公开的解决方案都需要全表扫描(或更糟)。
里克·詹姆斯

2
MySQL中真正的解析函数ROW_NUMBER,RANK,DESNSE_RANK的无耻自我推广解决方案
Kenneth Xu

Answers:


102

我想要每对(col1,col2)对具有最高col3的行。

这是一个按组的最大值,这是最常提出的SQL问题之一(因为它看起来应该很容易,但实际上并非如此)。

我经常为null-self-join充实:

SELECT t0.col3
FROM table AS t0
LEFT JOIN table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3
WHERE t1.col1 IS NULL;

“获取表中没有其他匹配col1,col2的行具有更高col3的行。” (您会注意到这一点,并且如果多行具有相同的col1,col2,col3,则大多数其他按组最大的解决方案将返回多行。如果这是一个问题,则可能需要一些后处理。)


2
但是,如果(col1,col2)对有col3的两个最大值,该怎么办?您最终将获得两行。
保罗

@Paul:是的!刚刚在tic答案中添加了关于此内容的注释。此后,通常可以随意在应用程序层中随意丢弃不需要的多余行,但是如果您有很多行都具有相同的col3,则可能会出现问题。
bobince

1
bobince,这种解决方案在SO上很受欢迎,但是我有一个问题。解决方案基本上与使用以下查询来尝试找到最大的id相同:SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;它是否不需要n*n/2 + n/2IS NULL比较才能找到单行?我没有看到任何优化吗?我试图在另一个话题中问比尔类似的问题,但他似乎忽略了它。
newtover 2012年

2
@Paul-要解决存在多个与每个组的最大值匹配的行而您只想抓取一行的情况,您总是可以在ON子句逻辑中添加主键来打破平局... SELECT t0.col3 FROM table AS t0左联接表AS t1 ON
乔恩·阿姆斯特朗

2
更具可读性,因为SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
wrschneider

204

MySQL中没有排名功能。您可以获得的最接近的结果是使用一个变量:

SELECT t.*, 
       @rownum := @rownum + 1 AS rank
  FROM YOUR_TABLE t, 
       (SELECT @rownum := 0) r

那么在我的情况下该如何工作?我需要两个变量,col1和col2分别一个?当col1更改时,col2需要以某种方式重置。

是。如果是Oracle,则可以使用LEAD函数在下一个值达到峰值。幸运的是,Quassnoi涵盖了您需要在MySQL中实现的逻辑


1
嗯....那我的情况如何?我需要两个变量,col1和col2分别一个?当col1更改时,col2需要以某种方式重置。
Paul

谢谢...就像我在上面说的,这个答案同样被bobince接受,但我只能打一个:-)
Paul

9
在同一语句中分配和读取用户定义的变量并不可靠。这在此处进行了记录:dev.mysql.com/doc/refman/5.0/en/user-variables.html:“通常,永远不要为用户变量分配值,也不要在同一条语句中读取该值。您可能会得到期望的结果,但这不能保证。涉及用户变量的表达式的求值顺序是不确定的,并可能根据给定语句中包含的元素而改变。”
罗兰·鲍曼

1
@Roland:我只测试了小型数据集,没有任何问题。太糟糕的MySQL尚未解决该功能-该请求自2008
OMG Ponies 2010年

2
Roland指出,这似乎是未定义的行为。例如,这给出了我尝试过的表的完全不正确的结果:SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
jberryman

81

我总是最终遵循这种模式。给定此表:

+------+------+
|    i |    j |
+------+------+
|    1 |   11 |
|    1 |   12 |
|    1 |   13 |
|    2 |   21 |
|    2 |   22 |
|    2 |   23 |
|    3 |   31 |
|    3 |   32 |
|    3 |   33 |
|    4 |   14 |
+------+------+

您可以得到以下结果:

+------+------+------------+
|    i |    j | row_number |
+------+------+------------+
|    1 |   11 |          1 |
|    1 |   12 |          2 |
|    1 |   13 |          3 |
|    2 |   21 |          1 |
|    2 |   22 |          2 |
|    2 |   23 |          3 |
|    3 |   31 |          1 |
|    3 |   32 |          2 |
|    3 |   33 |          3 |
|    4 |   14 |          1 |
+------+------+------------+

通过运行此查询,不需要定义任何变量:

SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j

希望有帮助!


1
如果列是VARCHAR或CHAR,那么如何使用这种结构处理呢?
Tushar 2014年

3
您太棒了,Mosty,我正在寻找这个东西
luckykrrish 2014年

只需使用您的row_number逻辑给出此答案。谢谢。
乌察夫2015年

@Tushar运营商<><=>=手柄CHAR和字母顺序VARCHAR数据类型; 我希望,这正是您想要的。
Alex

1
@AlmazVildanov您应该可以仅将此查询用作筛选出的子查询row_numbers <= 2 。非常感谢您的回答Mosty,非常好!
Zax

61
SELECT 
    @i:=@i+1 AS iterator, 
    t.*
FROM 
    tablename AS t,
    (SELECT @i:=0) AS foo

1
@OMG Ponies答案似乎缺少第一个:=。感谢您发布此彼得·约翰逊。
sholsinger

我猜(SELECT @i:= 0)AS foo应该是FROM语句中的第一个表,尤其是如果其他表使用子选择
andig 2013年

为什么甚至需要'.. as foo'?
汤姆·奇弗顿

@TomChiverton如果缺少它,则会得到:“错误代码:1248。每个派生表必须具有自己的别名”
ExStackChanger

1
这里的等级分配是完全不确定的,甚至都不能回答这个问题
jberryman

27

查阅本文,它展示了如何在MySQL中通过分区模拟SQL ROW_NUMBER()。我在WordPress实现中遇到了这种情况。我需要ROW_NUMBER(),但它不在那儿。

http://www.explodybits.com/2011/11/mysql-row-number/

本文中的示例使用按字段划分单个分区。要按其他字段进行分区,您可以执行以下操作:

  SELECT  @row_num := IF(@prev_value=concat_ws('',t.col1,t.col2),@row_num+1,1) AS RowNumber
         ,t.col1 
         ,t.col2
         ,t.Col3
         ,t.col4
         ,@prev_value := concat_ws('',t.col1,t.col2)
    FROM table1 t,
         (SELECT @row_num := 1) x,
         (SELECT @prev_value := '') y
   ORDER BY t.col1,t.col2,t.col3,t.col4 

使用concat_ws可处理null。我使用int,date和varchar针对3个字段对此进行了测试。希望这可以帮助。请查看该文章,因为它可以分解此查询并进行解释。


1
太棒了 这实际上是分区。非常方便
Stuart Watt 2015年

1
与自连接相比,这要高效得多,但是逻辑上存在问题,在计算row_num之前必须先执行顺序,也不需要concat。``SELECT @row_num:= IF(@ prev_col1 = t.col1 AND @ prev_col2 = t.col2),@ row_num + 1,1)AS RowNumber,t.col1,t.col2,t.col3,t.col4 ,@ prev_col1:= t.col1,@ prev_col2:= t.col2 FROM(SELECT * FROM table1 ORDER BY col1,col2,col3)t,(SELECT @row_num:= 1,@ prev_col1:='',@ prev_col2: = '')VAR```
肯尼斯·许

如果需要将其放入子查询中,则添加limit 18446744073709551615到force order by子句。
xmedeko

concat_ws带空字符串''是危险的:concat_ws('',12,3) = concat_ws('',1,23)。最好使用一些分隔符'_'或使用@Kenneth Xu解决方案。
xmedeko


25

从头至尾MySQL 8.0.0,您可以本机使用窗口函数。

1.4 MySQL 8.0的新增功能

窗口功能。

MySQL现在支持窗口函数,对于查询的每一行,它使用与该行相关的行来执行计算。这些包括诸如RANK(),LAG()和NTILE()之类的函数。此外,现在可以将几个现有的聚合函数用作窗口函数;例如SUM()和AVG()。

ROW_NUMBER()over_clause

返回其分区内当前行的编号。行数范围从1到分区行数。

ORDER BY影响行编号的顺序。如果没有ORDER BY,行号是不确定的。

演示:

CREATE TABLE Table1(
  id INT AUTO_INCREMENT PRIMARY KEY, col1 INT,col2 INT, col3 TEXT);

INSERT INTO Table1(col1, col2, col3)
VALUES (1,1,'a'),(1,1,'b'),(1,1,'c'),
       (2,1,'x'),(2,1,'y'),(2,2,'z');

SELECT 
    col1, col2,col3,
    ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1;

DBFiddle演示


1
叹息……终于!
Used_By_Already

15

我也将对Mosty Mostacho的解决方案投一票,对他的查询代码进行较小的修改:

SELECT a.i, a.j, (
    SELECT count(*) from test b where a.j >= b.j AND a.i = b.i
) AS row_number FROM test a

将会得到相同的结果:

+------+------+------------+
|    i |    j | row_number |
+------+------+------------+
|    1 |   11 |          1 |
|    1 |   12 |          2 |
|    1 |   13 |          3 |
|    2 |   21 |          1 |
|    2 |   22 |          2 |
|    2 |   23 |          3 |
|    3 |   31 |          1 |
|    3 |   32 |          2 |
|    3 |   33 |          3 |
|    4 |   14 |          1 |
+------+------+------------+

对于表:

+------+------+
|    i |    j |
+------+------+
|    1 |   11 |
|    1 |   12 |
|    1 |   13 |
|    2 |   21 |
|    2 |   22 |
|    2 |   23 |
|    3 |   31 |
|    3 |   32 |
|    3 |   33 |
|    4 |   14 |
+------+------+

唯一的区别是查询不使用JOIN和GROUP BY,而是依赖嵌套的select。


这应该更好吗?他们似乎都可能是二次方的,但是我不确定如何对EXPLAIN输出进行解释
jberryman '17

实际上,众所周知,嵌套选择在MySQL中没有得到很好的优化,因此此anwser仅用于演示查询技术。我想上面的基于变量的示例在大多数实际情况下效果更好。
abcdn

1
我不相信任何基于变量的答案实际上都在使用定义的行为...
jberryman

对不起,我不确定我是否理解了“定义的行为”的含义。您是说它不适合您,还是您担心它没有记录在案?
abcdn

1
“未定义的行为”表示未记录其工作和/或记录其不能保证工作。请参阅本页注释中的文档引号和链接。它可能会返回(令人惊讶地)想要/猜测/假设尺寸/幻想尺寸。对于某些实现的版本,Percona的程序员通过查看代码显示了使用CASE递增和使用变量的某些查询表达式可以正常工作。任何发行版都有可能改变。
philipxy

12

我将定义一个函数:

delimiter $$
DROP FUNCTION IF EXISTS `getFakeId`$$
CREATE FUNCTION `getFakeId`() RETURNS int(11)
    DETERMINISTIC
begin
return if(@fakeId, @fakeId:=@fakeId+1, @fakeId:=1);
end$$

然后我可以做:

select getFakeId() as id, t.* from table t, (select @fakeId:=0) as t2;

现在您没有子查询,而视图中没有该子查询。


具有一个限制:多次执行查询,对于相同的结果集,您将获得越来越多的falseIds
Stephan Richter

您可以发送set @fakeId = 0; 每次您要运行查询时,它都不是最优的,但是可以工作
jmpeace

如果删除DETERMINISTIC,则会发生一个非常奇怪的问题。然后在使用order by时fakeId不正确。为什么是这样?
克里斯·穆恩奇

8

在mysql中查询row_number

set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs

这可以用于UPDATE查询吗?我正在尝试,但是出现“列的数据被截断...”错误。
迭戈

1
如果有人对在UPDATE上使用它感兴趣,则必须将它用作子查询才能使用。UPDATE <表> SET <字段> =(SELECT \ @行号:= \ @行号+1)ORDER BY <您的订单栏>; 顺序列确定行的值顺序。
迭戈

8

在MySQL中没有像这样的功能rownumrow_num()但是解决方法如下:

select 
      @s:=@s+1 serial_no, 
      tbl.* 
from my_table tbl, (select @s:=0) as s;

4

我发现最有效的解决方案是使用子查询,如下所示:

SELECT 
    col1, col2, 
    (
        SELECT COUNT(*) 
        FROM Table1
        WHERE col1 = t1.col1
        AND col2 = t1.col2
        AND col3 > t1.col3
    ) AS intRow
FROM Table1 t1

只需将PARTITION BY列与“ =”进行比较,并用AND分隔。ORDER BY列将与“ <”或“>”进行比较,并以OR分隔。

我发现这是非常灵活的,即使有点昂贵。


4

行号功能不能被模仿。您可能会得到预期的结果,但是在某个阶段您很可能会感到失望。这是mysql文档说的:

对于其他语句,例如SELECT,您可能会得到期望的结果,但这不能保证。在下面的语句中,您可能认为MySQL将首先评估@a,然后再进行赋值:SELECT @a,@a:= @ a + 1,...; 但是,涉及用户变量的表达式的求值顺序是不确定的。

问候,乔治。


我不懂 “ @i:= @i + 1作为位置”如何不能直接替换“ ROW_NUMBER()超过(按sum(score)desc排序)作为位置”?
汤姆·奇弗顿

1
@TomChiverton因为未定义其行为,如手册中所述。
philipxy


2

我看不到涵盖“ PARTITION BY”部分的任何简单答案,所以这是我的:

SELECT
    *
FROM (
    select
        CASE WHEN @partitionBy_1 = l THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
        , @partitionBy_1:=l AS p
        , t.*
    from (
        select @row_number:=0,@partitionBy_1:=null
    ) as x
    cross join (
        select 1 as n, 'a' as l
        union all
        select 1 as n, 'b' as l    
        union all
        select 2 as n, 'b' as l    
        union all
        select 2 as n, 'a' as l
        union all
        select 3 as n, 'a' as l    
        union all    
        select 3 as n, 'b' as l    
    ) as t
    ORDER BY l, n
) AS X
where i > 1
  • ORDER BY子句必须反映您的ROW_NUMBER需求。因此,已经存在明显的局限性:您不能同时具有此格式的多个ROW_NUMBER“仿真”。
  • “计算列”的顺序很重要。如果您有mysql以另一顺序计算那些列,则可能不起作用。
  • 在这个简单的示例中,我只放置了一个,但是您可以包含多个“ PARTITION BY”部分

        CASE WHEN @partitionBy_1 = part1 AND @partitionBy_2 = part2 [...] THEN @row_number:=@row_number+1 ELSE @row_number:=1 END AS i
        , @partitionBy_1:=part1 AS P1
        , @partitionBy_2:=part2 AS P2
        [...] 
    FROM (
        SELECT @row_number:=0,@partitionBy_1:=null,@partitionBy_2:=null[...]
    ) as x

1

有点晚了,但也可能对寻求答案的人有所帮助...

在行/行数之间的示例-可以在任何SQL中使用的递归查询:

WITH data(row_num, some_val) AS 
(
 SELECT 1 row_num, 1 some_val FROM any_table --dual in Oracle
  UNION ALL
 SELECT row_num+1, some_val+row_num FROM data WHERE row_num < 20 -- any number
)
SELECT * FROM data
 WHERE row_num BETWEEN 5 AND 10
/

ROW_NUM    SOME_VAL
-------------------
5           11
6           16
7           22
8           29
9           37
10          46

2
抱歉,据我所知MySQL不支持通用表表达式
阿尔瓦罗·冈萨雷斯

现在这样...... @ÁlvaroGonzálezMySQL的8只支持CTE和窗口功能,所以这个答案并没有真正意义的使用较老版本的MySQL ..
雷蒙德Nijland

1

这允许在MySQL中实现与ROW_NUMBER()AND PARTITION BY提供的功能相同的功能

SELECT  @row_num := IF(@prev_value=GENDER,@row_num+1,1) AS RowNumber
       FirstName, 
       Age,
       Gender,
       @prev_value := GENDER
  FROM Person,
      (SELECT @row_num := 1) x,
      (SELECT @prev_value := '') y
  ORDER BY Gender, Age DESC

1

也有点晚,但今天我有同样的需求,所以我在Google上进行搜索,最后在Pinal Dave的文章http://blog.sqlauthority.com/2014/03/09/mysql-reset-row中找到了一种简单的通用方法每个组分区的编号按行号/

我想关注Paul最初的问题(这也是我的问题),因此我将解决方案作为一个工作示例进行了总结。

因为我们要划分两列,所以我将在迭代期间创建一个SET变量,以识别是否启动了新的组。

SELECT col1, col2, col3 FROM (
  SELECT col1, col2, col3,
         @n := CASE WHEN @v = MAKE_SET(3, col1, col2)
                    THEN @n + 1 -- if we are in the same group
                    ELSE 1 -- next group starts so we reset the counter
                END AS row_number,
         @v := MAKE_SET(3, col1, col2) -- we store the current value for next iteration
    FROM Table1, (SELECT @n := 0, @v := NULL) r -- helper table for iteration with startup values
   ORDER BY col1, col2, col3 DESC -- because we want the row with maximum value
) x WHERE row_number = 1 -- and here we select exactly the wanted row from each group

3表示在MAKE_SET的第一个参数上,我希望两个值都在SET中(3 = 1 | 2)。当然,如果我们没有两个或更多个构成组的列,则可以消除MAKE_SET操作。构造完全相同。这对我来说是必需的。非常感谢Pinal Dave的清晰示范。


1
请注意,ORDER BY在子查询中可以忽略(请参阅mariadb.com/kb/en/mariadb/…)。建议的解决方案是添加LIMIT 18446744073709551615到子查询中,这将强制排序。但是,这可能会导致性能问题,并且对于真正
抓紧

1

这也可以是一个解决方案:

SET @row_number = 0;

SELECT 
    (@row_number:=@row_number + 1) AS num, firstName, lastName
FROM
    employees

它没有进行任何分区,并且与更高引用的答案没有明显不同
Caius Jard

1

8.0+版本开始,MySQL支持ROW_NUMBER()

如果使用MySQL 8.0或更高版本,请检查ROW_NUMBER()函数。否则,您将模拟ROW_NUMBER()函数。

row_number()是一种排序函数,它返回一行的序号,第一行从1开始。

对于旧版本,

SELECT t.*, 
       @rowid := @rowid + 1 AS ROWID
  FROM TABLE t, 
       (SELECT @rowid := 0) dummy;

1

重要提示:请考虑升级到MySQL 8+,并使用已定义和记录的ROW_NUMBER()函数,并抛弃与功能受限的旧版MySQL相关的旧代码

现在是这些黑客之一:

此处大部分/全部使用查询中变量的答案似乎忽略了文档所说的事实(表述):

不要依赖SELECT列表中从上到下顺序评估的项目。不要在一个SELECT项中分配变量,而在另一项中使用它们

因此,他们有可能会得出错误的答案,因为他们通常会做

select
  (row number variable that uses partition variable),
  (assign partition variable)

如果对这些进行了自下而上的评估,则行号将停止工作(无分区)

因此,我们需要使用具有一定执行顺序的东西。在以下情况下输入案例:

SELECT
  t.*, 
  @r := CASE 
    WHEN col = @prevcol THEN @r + 1 
    WHEN (@prevcol := col) = null THEN null
    ELSE 1 END AS rn
FROM
  t, 
  (SELECT @r := 0, @prevcol := null) x
ORDER BY col

如大纲ld所示,prevcol的分配顺序很重要-必须先将prevcol与当前行的值进行比较,然后才能从当前行为其分配值(否则它将是当前行的col值,而不是前一行的col值) 。

这是如何组合在一起的:

  • 评估第一个WHEN。如果此行的col与上一行的col相同,则@r递增并从CASE返回。此返回的led值存储在@r中。MySQL的一个功能是赋值将分配给@r的新值返回到结果行中。

  • 对于结果集的第一行,@prevcol为null(在子查询中被初始化为null),因此该谓词为false。每次col更改时,该第一个谓词也返回false(当前行与上一行不同)。这将导致对第二个WHEN进行评估。

  • 第二个WHEN谓词始终为false,它纯粹是为@prevcol分配一个新值而存在。由于此行的col与上一行的col不同(我们知道这是因为如果相同,则将使用第一个WHEN),因此我们必须分配新值以使其下次进行测试。因为进行了赋值,然后将赋值的结果与null进行比较,并且等于null的任何内容均为false,所以该谓词始终为false。但是至少要评估它的工作是保留此行中col的值,因此可以根据下一行的col值对其进行评估

  • 因为第二个WHEN为假,这意味着在我们要按(col)划分的列已更改的情况下,正是ELSE为@r提供了新值,从而从1重新开始编号

我们将遇到以下情况:

SELECT
  t.*, 
  ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
  t

具有以下一般形式:

SELECT
  t.*, 
  @r := CASE 
    WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1 
    WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
    ELSE 1 
  END AS rn
FROM
  t, 
  (SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX

脚注:

  • pcol中的p表示“分区”,ocol中的o表示“顺序”-在一般形式中,我从变量名中删除了“ prev”以减少视觉混乱

  • 周围的括号(@pcolX := colX) = null很重要。没有它们,您将为@pcolX分配null,事情将停止工作

  • 折衷的是,结果集也必须按分区列排序,以便比较前一列。因此,您不能将行号按一列排序,而将结果集按另一列排序。您也许可以使用子查询来解决此问题,但是我相信文档还指出,除非使用LIMIT,否则子查询的排序可能会被忽略,这可能会影响性能

  • 除了测试该方法是否有效外,我还没有深入研究它,但是如果存在第二个WHEN中的谓词将被优化的风险(与null相比的任何事物都是null / false,那么为什么要麻烦运行赋值)而不执行,它也会停止。根据我的经验,这似乎没有发生,但我很乐意接受评论并提出解决方案(如果可能的话)

  • 在创建@pcolX变量的子查询中,将创建@pcolX的空值强制转换为列的实际类型可能是明智的: select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)


没有任何理由。就像分配给同一变量并从中读取的其他答案一样。
philipxy

您可以提供更多详细信息吗?
Caius Jard,

在此页面上查看我的其他评论。谷歌搜索“ site:stackoverflow.com“ philipxy” mysql变量(设置或分配或分配或写入)读取':我的回答关于此问题的评论中我的链接的错误报告,其中接受的答案立即引用了手册在主张中可以做一些与之矛盾的事情。阅读手册“重新变量和重新分配”。
philipxy


我了解您的关注
Caius Jard

0

这不是最可靠的解决方案-但是,如果您只是想在仅包含几个不同值的字段上创建分区等级,那么当逻辑具有所需数量的变量时,在某些情况下使用它可能会很不明智。

过去,这样的事情对我有用:

SELECT t.*, 
   CASE WHEN <partition_field> = @rownum1 := @rownum1 + 1 
     WHEN <partition_field> = @rownum2 := @rownum2 + 1 
     ...
     END AS rank
FROM YOUR_TABLE t, 
   (SELECT @rownum1 := 0) r1, (SELECT @rownum2 := 0) r2
ORDER BY <rank_order_by_field>
;

希望有道理/有帮助!


-1

当我们有多于一列时,这对我来说非常适合创建RowNumber。在这种情况下为两列。

SELECT @row_num := IF(@prev_value= concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`), @row_num+1, 1) AS RowNumber, 
    `Fk_Business_Unit_Code`,   
    `NetIQ_Job_Code`,  
    `Supervisor_Name`,  
    @prev_value := concat(`Fk_Business_Unit_Code`,`NetIQ_Job_Code`)  
FROM (SELECT DISTINCT `Fk_Business_Unit_Code`,`NetIQ_Job_Code`,`Supervisor_Name`         
      FROM Employee    
      ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`, `Supervisor_Name` DESC) z,  
(SELECT @row_num := 1) x,  
(SELECT @prev_value := '') y  
ORDER BY `Fk_Business_Unit_Code`, `NetIQ_Job_Code`,`Supervisor_Name` DESC

-3
set @i = 1;  
INSERT INTO ARG_VALUE_LOOKUP(ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,UPDATE_TIMESTAMP,UPDATE_USER,VER_NBR,OBJ_ID) 
select @i:= @i+1 as ARG_VALUE_LOOKUP_ID,ARGUMENT_NAME,VALUE,DESCRIPTION,CURRENT_TIMESTAMP,'admin',1,UUID() 
FROM TEMP_ARG_VALUE_LOOKUP 
order by ARGUMENT_NAME;

1
请尝试格式化所有答案,并提供有关您要执行的操作的其他上下文。目前,仅是格式不正确的文字。
Yannick Meeus,2015年

2
这似乎与原始问题没有任何关系。如果您有自己的问题,请另行询问。
Jeroen Mostert

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.