ROW_NUMBER()in MySQL
-
19-09-2019 - |
题
是有一个很好的方式在MySQL复制SQL服务器的功能 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)
对。
解决方案
我想要的行与单一最高col3每个(1列,第2列)对。
这是一个 小最大, 一个最常问SQL问题(因为它看来似乎应该很容易,但实际上这种不).
我经常丰满的null-自加入:
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;
"得到表中的行为没有任何其他行匹配1列,第2列有一个高col3." (你们会注意到这个和其他大多数的小大方案将返回多行如果多于一个行具有相同的1列,第2列,col3.如果这是一个问题可能需要一些后处理。)
其他提示
没有排名中的功能MySQL.最近你可以得到的是使用一个变量:
SELECT t.*,
@rownum := @rownum + 1 AS rank
FROM YOUR_TABLE t,
(SELECT @rownum := 0) r
因此,如何将这项工作在我的情况?我需要两个变量,每一个的1列和第2列?第2列将需要重新设置以某种方式在1列改变..?
是的。如果是甲骨文,你可以使用导致函数高峰期在下一个价值。值得庆幸的是,Quassnoi涵盖 逻辑为什么你需要实现在MySQL.
我总是以下这种模式。鉴于这表:
+------+------+
| 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
希望这可以帮助!
SELECT
@i:=@i+1 AS iterator,
t.*
FROM
tablename AS t,
(SELECT @i:=0) AS foo
看看这篇文章,这显示了如何模仿SQL ROW_NUMBER()有一个分区通过中MySQL.我跑进这个非常相同的情况下在了一个字的实施。我需要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处理空。我测试这对3个字段,使用一个int、日期和varchar。希望这会有所帮助。检查了文章,因为它打破了这种查询并解释了它。
从 MySQL 8.0.0
和你上面可以本身使用窗口的功能。
窗口的功能。
MySQL现在支持窗口的功能是,对每个行查询,执行一个计算使用的行有关该行。这些包括功能,例如排名(),滞后(),和NTILE().此外,现有的几个集合体的功能,现在可以作为窗口的功能;例如,SUM()和平均().
返回的数量目前的行在其分区。行数的范围为1到的数量的分行。
为了通过影响了在其行编号。没有为由,排的编号是不确定的。
演示:
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;
我也要投票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 |
+------+------+
唯一的区别在于查询不使用加入和组,依靠的嵌套选择,而不是。
我将定义一个功能:
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;
现在你没有子查询,其中不能有中景。
没有功能等 rownum
, row_num()
在MySQL但是围绕如下:
select
@s:=@s+1 serial_no,
tbl.*
from my_table tbl, (select @s:=0) as s;
查询row_number在mysql
set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs
解决我找到工作,最好是采用一种查询这样的:
SELECT
col1, col2,
(
SELECT COUNT(*)
FROM Table1
WHERE col1 = t1.col1
AND col2 = t1.col2
AND col3 > t1.col3
) AS intRow
FROM Table1 t1
该分区列只得到比较'='和分离。为了通过列将与'<'或'>',并通过分离或.
我已经发现这是非常灵活,即使是一点点代价高昂。
The rownumber功能不能模仿.你可能会得到预期的结果,但你会最有可能得到失望,在某个阶段。这是什么mysql文件说:
对于其他语句,例如选择的,你可能会获得预期的结果,但这不能保证。在下面的发言,你可能会认为MySQL将评估@第一然后做一个任务二:选择@a、@a:=@a+1,...;然而,为了评价表达的涉及用户变量是不确定的。
问候, 格奥尔.
只10.2被执行"窗口的功能",包括秩(),ROW_NUMBER()以及一些其他的东西:
https://mariadb.com/kb/en/mariadb/window-functions/
基于谈Percona生活的这个月,他们是合理优化。
语法相同的代码,在这个问题。
我没有看到任何简单的答案复盖"分区"的一部分,因此,这里的地雷:
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
- 为了通过条款必须反映ROW_NUMBER的需要。因此已经有了一个明确的限制:你不能有几个ROW_NUMBER"模拟"的这一形式,在同一时间。
- 秩序"的计算列" 事项.如果你有mysql计算那些列于另一份订单,则可能无法工作。
在这个简单的例子,我只有放一个,但你可以几个"区通过"部分
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
有点晚但还可以帮助人寻找的答案...
行之间/row_number例递归的查询,可以使用任何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
这使得相同的功能,ROW_NUMBER()和分区通过提供实现MySQL
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
还有点晚但是今天我有同样的需要,所以我在谷歌搜索和最后一个简单的一般方法在这里找到在皮纳尔Dave的文章 http://blog.sqlauthority.com/2014/03/09/mysql-reset-row-number-for-each-group-partition-by-row-number/
我希望把重点放在保罗原来的问题(这是我的问题),所以我总结一下我的解决方案作为工作例子。
因为我们想要分区超过两个专栏中,我将建立一个设置期间可变的迭代要确定如果一个新的小组是开始。
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,我想要两个价值在设置(3=的1/2).当然,如果我们没有两个或两个以上的列修建的团体,我们可以消除MAKE_SET操作。建设是完全一样的。这是为我工作,作为必需的。非常感谢皮纳尔戴夫他明确的示范。
这也可能是一个解决方案:
SET @row_number = 0;
SELECT
(@row_number:=@row_number + 1) AS num, firstName, lastName
FROM
employees
MySQL支持ROW_NUMBER() 由于版本 8.0+.
如果你使用MySQL8.0或后来,检查出来ROW_NUMBER()function.否则,你模仿ROW_NUMBER()function.
The row_number()是一个排名的功能返回的顺序号排,从1开始的第一行。
老年版本,
SELECT t.*,
@rowid := @rowid + 1 AS ROWID
FROM TABLE t,
(SELECT @rowid := 0) dummy;
重要的是:请考虑提升到MySQL8+和使用的定义和记录ROW_NUMBER()功能和沟老黑客绑到一个功能有限的古代版本的MySQL
现在这里有一个这些黑客:
答案在这里,用于查询的变量,主要是/似乎都忽略的事实,该文件说(意译):
不要依靠项目,在选择清单正在进行评估,以便从上到下。不分配变量中的一个选项,并使用他们在另外一个
因此,有一种风险,他们将推出了错误的答案,因为它们通常做的
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值)。
这里是如何结合在一起:
第一时进行评估。如果这行的柱是相同的前行的col然后@r递增和返回的情况。这返回导致价值是存在@r.这是一个功能的MySQL分配返回的新值为什么被分配到@r成的结果行。
第一行的结果,@prevcol是空(它是初始化到空,在的查询)因此,这谓词是虚假的。这第一谓词也返回假,每次山口的变化(流行是不同于以前的行)。这引起第二次当进行评估。
第二,当谓总是虚假的,并且它的存在纯粹分配一个新的价值@prevcol.因为这一行列的是不同的,前一行的col(我们知道这一点,因为如果它是相同的,第一时将已使用),我们已经分配的新的价值,以保持它用于测试下一步的时间。因为分配制成,然后将结果转让与空,以及任何等同于空是虚假的,这谓总是错误的。但至少在评估这样的工作保持价值的col从这种排,使它能够评价对下一行的col值
因为第二时是假的,它意味着在情况柱我们分区的(col)已经改变,这是他给出了一个新的价值@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
脚注:
P在pcol装置"分区",在ocol装置"以"在一般形式,我放弃了"前"从可变名称,以减少视觉混乱
方括号
(@pcolX := colX) = null
都是重要的。没有他们你会分配null@pcolX事情停止工作这是一个折衷,结果设置必须命令通过该分区列过,对于以前列比较的工作。你不能因此有你rownumber下令根据一个塔但你的结果设定的命令的另一个你可能能够解决这个带子查询,但我相信,该文件还指出,子查询的排序可能被忽视,除非限制使用和这可能会影响性能
我还没有深入研究了它超出测试的方法工作,但如果有一种风险,即所谓的第二时将优化的程(任何东西比null is null/false那么,为什么打扰运行的分配)和不被执行,它也停止。这似乎不会发生在我的体验,但我会很乐意接受意见,并提出解决方案如果可以合理地发生
它可能是明智的投的空值,创建@pcolX的实际类型分列,在查询,创建@pcolX变量,即:
select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
这项工作完美地为我创造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
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;
SELECT
col1, col2,
count(*) as intRow
FROM Table1
GROUP BY col1,col2
ORDER BY col3 desc