在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,以获取每个(col1, col2)
对中最高col3
的单行。
在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,以获取每个(col1, col2)
对中最高col3
的单行。
MySQL中没有排名功能,最接近的方法是使用变量:
SELECT t.*,
@rownum := @rownum + 1 AS rank
FROM YOUR_TABLE t,
(SELECT @rownum := 0) r
那么在我的情况下该怎么办?我需要两个变量,一个用于col1,另一个用于col2?当col1更改时,col2需要进行某种重置..?
是的。如果使用Oracle,您可以使用LEAD函数查看下一个值。幸运的是,Quassnoi涵盖了您需要在MySQL中实现的逻辑。
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我想要每个(col1, col2) 对中col3最高的一行。
这是一个组内最大值问题,这是最常见的SQL问题之一(因为似乎很简单,但实际上不太容易)。
我经常选择使用空自连接:
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,则会返回多个行。如果这是个问题,你可能需要一些后处理。)
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
是否需要n*n / 2 + n/2
个IS NULL比较才能找到单行?是否发生了我没有看到的任何优化?我试图在另一个线程中向Bill提出类似的问题,但他似乎忽视了它。 - newtoverSELECT t0.col3
FROM table AS t0
LEFT JOIN table AS t1
ON t0.col1 = t1.col1
AND t0.col2 = t1.col2
AND (t1.col3, t1.pk) > (t0.col3, t0.pk)
WHERE t1.col1 IS NULL
;
- Jon Armstrong - XgcSELECT 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我总是遵循这个模式。给定这张表:
+------+------+
| 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
<
、>
、<=
、>=
按字母顺序处理CHAR和VARCHAR数据类型;我认为这正是你要找的。 - alexwhere row_number <= 2
吗? 如何加? - gevarawebSELECT
@i:=@i+1 AS iterator,
t.*
FROM
tablename AS t,
(SELECT @i:=0) AS foo
从 MySQL 8.0.0
版本开始,您可以原生地使用窗口函数。
窗口函数。
MySQL现在支持窗口函数,对于来自查询的每一行,它们使用与该行相关的行执行计算。这些包括RANK()、LAG()和NTILE()等函数。此外,现有的几个聚合函数现在也可以用作窗口函数;例如,SUM()和AVG()。
返回其分区内当前行的编号。行编号范围从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;
看看这篇文章,它展示了如何在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
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
- Kenneth Xu''
的 concat_ws
是危险的:concat_ws('',12,3) = concat_ws('',1,23)
。最好使用一些分隔符 '_'
或使用 @Kenneth Xu 的解决方案。 - xmedeko我也会投票支持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,而是依靠嵌套选择语句。
I would define a function:
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;
现在你没有子查询,因为视图中不能有子查询。
在 MySQL 中查询行号
set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs
MySQL 中没有像 rownum
或 row_num()
这样的函数,但可以通过以下方式实现相同的功能:
select
@s:=@s+1 serial_no,
tbl.*
from my_table tbl, (select @s:=0) as s;