[英]MySQL 5.6 - DENSE_RANK like functionality without Order By
我有这样一张桌子:
+------+-----------+
|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
值应该按groupVarian
的顺序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版本<8.0 ( OP的版本是5.6 ):
问题陈述看起来需要在groupVarian
DENSE_RANK功能; 但事实并非如此。 正如@Gordon Linoff解释的那样 :
您似乎希望按照它们在数据中出现的顺序枚举它们。
假设您的表名是t
(请相应地更改您的代码的表和字段名称)。 这是一种利用会话变量 ( 对于旧版本的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
功能。 但是,下面的查询效率更高,因为它创造了较小的派生表 ,并避免JOIN上groupVarian
:
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
你可以使用DENSE_RANK
(MySQL 8.0):
SELECT *, CONCAT('v', DENSE_RANK() OVER(ORDER BY groupVarian)) AS namevarian
FROM tab
ORDER BY CaseID;
基本上,您想要枚举变体。 如果您只想要一个数字,那么您可以使用最小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不保证在排序之前发生变量赋值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.