MySQL 5.6 - DENSE_RANK 类似没有 Order By 的功能
Posted
技术标签:
【中文标题】MySQL 5.6 - DENSE_RANK 类似没有 Order By 的功能【英文标题】:MySQL 5.6 - DENSE_RANK like functionality without Order By 【发布时间】:2018-09-16 09:46:36 【问题描述】:我有一张这样的桌子:
+------+-----------+
|caseID|groupVarian|
+------+-----------+
|1 |A,B,C,D,E |
+------+-----------+
|2 |A,B,N,O,P |
+------+-----------+
|3 |A,B,N,O,P |
+------+-----------+
|4 |A,B,C,D,F |
+------+-----------+
|5 |A,B,C,D,E |
+------+-----------+
我想获得一个新列nameVarian
,这样相同的groupVarian
值具有由nameVarian
表示的相同排名(例如:v1、v2 等)。但是,分配给特定groupVarian
的nameVarian
值应该按照caseID
的顺序(按照它们在表格中出现的顺序)。
输出应该是这样的:
+------+-----------+----------+
|caseID|groupVarian|namevarian
+------+-----------+----------+
|1 |A,B,C,D,E |v1 |
+------+-----------+----------+
|2 |A,B,N,O,P |v2 |
+------+-----------+----------+
|3 |A,B,N,O,P |v2 |
+------+-----------+----------+
|4 |A,B,C,D,F |v3 |
+------+-----------+----------+
|5 |A,B,C,D,E |v1 |
+------+-----------+----------+
【问题讨论】:
你的 mysql 版本是多少? @madhur baiya 5.6 @MadhurBhaiya 好的,我试试,谢谢 【参考方案1】:对于 MySQL 版本 (OP's version is 5.6):
问题陈述看起来需要DENSE_RANK 功能而不是groupVarian
;然而事实并非如此。 As explained by @Gordon Linoff:
您似乎希望按照它们在 数据。
假设您的表名是t
(请为您的代码相应地更改表名和字段名)。这是一个approach utilizing session variables(对于旧版本的 MySQL),给出了所需的结果(DB Fiddle):
SET @row_number = 0;
SELECT t3.caseID,
t3.groupVarian,
CONCAT('v', t2.num) AS nameVarian
FROM
(
SELECT
(@row_number:=@row_number + 1) AS num,
t1.groupVarian
FROM
(
SELECT DISTINCT groupVarian
FROM t
ORDER BY caseID ASC
) AS t1
) AS t2
INNER JOIN t AS t3
ON t3.groupVarian = t2.groupVarian
ORDER BY t3.caseID ASC
另外:我之前模拟DENSE_RANK
功能的尝试效果很好。尽管也可以稍微调整以前的查询以实现DENSE_RANK
功能。但是,以下查询更有效,因为它创建了较小的派生表,并避免了groupVarian
上的JOIN:
SET @row_number = 1;
SET @group_varian = '';
SELECT inner_nest.caseID,
inner_nest.groupVarian,
CONCAT('v', inner_nest.num) as nameVarian
FROM (
SELECT
caseID,
@row_number:=CASE
WHEN @group_varian = groupVarian THEN @row_number
ELSE @row_number + 1
END AS num,
@group_varian:=groupVarian as groupVarian
FROM
t
ORDER BY groupVarian
) AS inner_nest
ORDER BY inner_nest.caseID ASC
【讨论】:
我尝试过,但如果 groupVarian 列中的值与其他行具有相同的值,则变体名称具有相同的变体名称。 @daud 你得到了什么输出? 如果 grupVarian 的值相同,则名称 varian 的值相同,例如请参阅我的帖子。感谢您的帮助 @daud 请在运行我的查询后发布您得到的输出?确保SET
命令是 start 也运行
@daud 终于找到了解决方案。请检查更新的答案!应该 100% 工作 :) 不要忘记相应地更改表和字段名称。【参考方案2】:
你可以使用DENSE_RANK
(MySQL 8.0):
SELECT *, CONCAT('v', DENSE_RANK() OVER(ORDER BY groupVarian)) AS namevarian
FROM tab
ORDER BY CaseID;
db<>fiddle demo
【讨论】:
太棒了,但我仍在我的服务器上使用 mysql 5.7。谢谢你的帮助。我很感激【参考方案3】:基本上,您想枚举变体。如果你只想要一个数字,那么你可以使用最小 id:
select t.*, min_codeId as groupVariantId
from t join
(select groupVariant, min(codeId) as min_codeId
from t
group by groupVariant
) g
on t.groupVariant = g.groupVariant;
但这并不是你想要的。您似乎希望它们按它们在数据中出现的顺序进行枚举。为此,您需要变量。这有点棘手,但是:
select t.*, rn as groupVariantId
from t join
(select g.*,
(@rn := if(@gv = groupvariant, @gv,
if(@gv := groupvariant, @gv+1, @gv+1)
)
) as rn
from (select groupVariant, min(codeId) as min_codeId
from t
group by groupVariant
order by min(codeId)
) g cross join
(select @gv := '', @rn := 0) params
) g
on t.groupVariant = g.groupVariant;
使用变量很棘手。一个重要的考虑因素:MySQL 不保证SELECT
中表达式的求值顺序。这意味着不应在一个表达式中分配一个变量,然后在另一个表达式中使用它们——因为它们可能以错误的顺序计算(另一个答案有这个错误)。
此外,order by
需要发生在子查询中。 MySQL 不保证变量赋值发生在排序之前。
【讨论】:
以上是关于MySQL 5.6 - DENSE_RANK 类似没有 Order By 的功能的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 从 DENSE_RANK() 结果更新相同的表字段
MySQL:与dense_rank()over()的group by和partition的差异输出?
MySQL - 排序函数 Rank() Over()Dense_rank() Over()Row_number() Over()