Pau*_*aul 268 mysql sql row-number rank greatest-n-per-group
MySQL是否有一种很好的方式来复制SQL Server功能ROW_NUMBER()?
例如:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Run Code Online (Sandbox Code Playgroud)
然后,我可以,例如,添加一个限制intRow为1 的条件,以获得col3每(col1, col2)对最高的单行.
OMG*_*ies 198
MySQL中没有排名功能.你可以得到的最接近的是使用一个变量:
SELECT t.*,
@rownum := @rownum + 1 AS rank
FROM YOUR_TABLE t,
(SELECT @rownum := 0) r
Run Code Online (Sandbox Code Playgroud)
那么在我的案例中如何运作呢?我需要两个变量,col1和col2各有一个?当col1改变时,Col2需要以某种方式重置..?
是.如果是Oracle,则可以使用LEAD函数在下一个值处达到峰值.值得庆幸的是,Quassnoi涵盖了您需要在MySQL中实现的逻辑.
bob*_*nce 99
我希望每个(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;
Run Code Online (Sandbox Code Playgroud)
"获取表格中没有其他行匹配col1的行,col2具有更高的col3."(您会注意到这一点,如果多行具有相同的col1,则大多数其他groupwise-maximum解决方案将返回多行,col2 ,col3.如果这是一个问题,你可能需要一些后期处理.)
Mos*_*cho 80
我总是最终遵循这种模式.鉴于此表:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
Run Code Online (Sandbox Code Playgroud)
你可以得到这个结果:
+------+------+------------+
| 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 |
+------+------+------------+
Run Code Online (Sandbox Code Playgroud)
通过运行此查询,不需要定义任何变量:
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
Run Code Online (Sandbox Code Playgroud)
希望有所帮助!
Pet*_*son 58
SELECT
@i:=@i+1 AS iterator,
t.*
FROM
tablename AS t,
(SELECT @i:=0) AS foo
Run Code Online (Sandbox Code Playgroud)
小智 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
Run Code Online (Sandbox Code Playgroud)
使用concat_ws处理null.我使用int,date和varchar对3个字段进行了测试.希望这可以帮助.查看文章,因为它打破了这个查询并解释它.
Luk*_*zda 22
从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;
Run Code Online (Sandbox Code Playgroud)
abc*_*cdn 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
Run Code Online (Sandbox Code Playgroud)
哪个会得到相同的结果:
+------+------+------------+
| 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 |
+------+------+------------+
Run Code Online (Sandbox Code Playgroud)
对于表:
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
Run Code Online (Sandbox Code Playgroud)
唯一的区别是查询不使用JOIN和GROUP BY,而是依赖于嵌套选择.
Qui*_*ncy 12
我会定义一个函数:
delimiter $$
DROP FUNCTION IF EXISTS `getFakeId`$$
CREATE FUNCTION `getFakeId`() RETURNS int(11)
DETERMINISTIC
begin
return if(@fakeId, @fakeId:=@fakeId+1, @fakeId:=1);
end$$
Run Code Online (Sandbox Code Playgroud)
然后我可以这样做:
select getFakeId() as id, t.* from table t, (select @fakeId:=0) as t2;
Run Code Online (Sandbox Code Playgroud)
现在您没有子视图,视图中没有子查询.
小智 8
查询mysql中的row_number
set @row_number=0;
select (@row_number := @row_number +1) as num,id,name from sbs
Run Code Online (Sandbox Code Playgroud)
在MySQL中没有任何功能rownum,row_num()但是周围的方式如下:
select
@s:=@s+1 serial_no,
tbl.*
from my_table tbl, (select @s:=0) as s;
Run Code Online (Sandbox Code Playgroud)
重要提示:请考虑升级到 MySQL 8+ 并使用已定义和记录的 ROW_NUMBER() 函数,并放弃与功能有限的旧版本 MySQL 相关的旧技巧
现在这是其中之一:
这里大部分/全部使用查询变量的答案似乎忽略了文档所说的事实(释义):
不要依赖于按从上到下的顺序评估 SELECT 列表中的项目。不要在一个 SELECT 项中分配变量并在另一项中使用它们
因此,他们有可能给出错误答案,因为他们通常会做
select
(row number variable that uses partition variable),
(assign partition variable)
Run Code Online (Sandbox Code Playgroud)
如果从下往上评估这些,行号将停止工作(无分区)
所以我们需要使用有保证执行顺序的东西。输入案例:
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
Run Code Online (Sandbox Code Playgroud)
作为概述 ld,prevcol 的分配顺序很重要 - 在我们为当前行分配值之前,必须将 prevcol 与当前行的值进行比较(否则它将是当前行的 col 值,而不是前一行的 col 值) 。
这是它们如何组合在一起的:
第一个 WHEN 被评估。如果该行的 col 与前一行的 col 相同,则 @r 递增并从 CASE 返回。该返回值存储在@r 中。MySQL 的一个功能是,赋值会将分配给 @r 的新值返回到结果行中。
对于结果集上的第一行,@prevcol 为 null(它在子查询中初始化为 null),因此该谓词为 false。每次 col 更改时,第一个谓词也会返回 false(当前行与前一行不同)。这会导致评估第二个 WHEN。
第二个 WHEN 谓词始终为 false,它的存在纯粹是为了向 @prevcol 分配新值。因为这一行的 col 与前一行的 col 不同(我们知道这一点,因为如果它相同,则将使用第一个 WHEN),因此我们必须分配新值以保留它以供下次测试。因为先进行赋值,然后将赋值结果与 null 进行比较,而与 null 等同的任何内容都是 false,因此该谓词始终为 false。但至少评估它做了保留该行的 col 值的工作,因此可以根据下一行的 col 值对其进行评估
因为第二个 WHEN 为 false,这意味着在我们分区所依据的列 (col) 已更改的情况下,是 ELSE 为 @r 提供新值,从 1 重新开始编号
我们遇到这样的情况:
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
t
Run Code Online (Sandbox Code Playgroud)
具有一般形式:
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
Run Code Online (Sandbox Code Playgroud)
脚注:
pcol 中的 p 表示“分区”,ocol 中的 o 表示“顺序” - 在一般形式中,我从变量名称中删除了“prev”以减少视觉混乱
周围的括号(@pcolX := colX) = null很重要。如果没有它们,您会将 null 分配给 @pcolX 并且事情会停止工作
这是一个折衷方案,结果集也必须按分区列排序,以便与前一列进行比较才能计算出来。因此,您不能根据一列对行号进行排序,但将结果集排序到另一列您也许可以使用子查询来解决此问题,但我相信文档还指出,除非使用 LIMIT,否则可能会忽略子查询排序,这可能会影响表现
除了测试该方法是否有效之外,我没有深入研究它,但是如果存在第二个 WHEN 中的谓词将被优化掉的风险(与 null 相比的任何内容都是 null/false,所以为什么还要运行分配)并且不执行,它也停止。根据我的经验,这似乎不会发生,但如果可以合理地发生,我会很乐意接受评论并提出解决方案
在创建 @pcolX 变量的子查询中,将创建 @pcolX 的空值转换为列的实际类型可能是明智的,即:select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
| 归档时间: |
|
| 查看次数: |
488527 次 |
| 最近记录: |