[英]How do I set the record's position relative to a group in SQL?
我有一系列可以按group_id
分组的group_id
记录示例:
╭───╥──────────┬───────────────────╮
│id ║ group_id │ position_in_group │
╞═══╬══════════╪═══════════════════╡
│ 1 ║ 2 │ null │
│ 2 ║ 1 │ null │
│ 3 ║ 1 │ null │
│ 4 ║ 1 │ null │
│ 5 ║ 2 │ null │
│ 6 ║ 2 │ null │
│ 7 ║ 3 │ null │
│ 8 ║ 3 │ null │
│ 9 ║ 3 │ null │
└───╨──────────┴───────────────────┘
我想为每个记录设置position_in_group
。 如果I GROUP BY group_id
,则它是记录在组内的位置。
例如:在id为1的组中,id为2的记录是第一条记录,因此其position_in_group
为1。
决赛桌将是:
╭───╥──────────┬───────────────────╮
│id ║ group_id │ position_in_group │
╞═══╬══════════╪═══════════════════╡
│ 1 ║ 2 │ 1 │
│ 2 ║ 1 │ 1 │
│ 3 ║ 1 │ 2 │
│ 4 ║ 1 │ 3 │
│ 5 ║ 2 │ 2 │
│ 6 ║ 2 │ 3 │
│ 7 ║ 3 │ 1 │
│ 8 ║ 3 │ 2 │
│ 9 ║ 3 │ 3 │
└───╨──────────┴───────────────────┘
有什么办法可以在SQL查询中执行此操作?
一种方法是使用变量。 在MySQL中有点挑战,但看起来可能像这样:
set @g := -1;
set @rn := 0;
update t
set position_in_group = (@rn := if(@g = group_id, @rn + 1,
if(@g := group_id, 1, 1)
)
)
order by group_id, id;
注意:您需要与update
语句分开分别初始化变量,因为MySQL不支持在同一update
语句中进行联接和排序。
无需存储此数据...
SELECT id
, group_id
, rank
FROM
( SELECT id
, group_id
, CASE WHEN group_id = @prev THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=group_id prev
FROM my_table x
, (SELECT @i:=1,@prev:=null) vars
ORDER
BY group_id
, id
) a
ORDER
BY id;
...但是如果您真的想...
UPDATE my_table a
JOIN
( SELECT id
, group_id
, CASE WHEN group_id = @prev THEN @i:=@i+1 ELSE @i:=1 END rank
, @prev:=group_id prev
FROM my_table x
, (SELECT @i:=1,@prev:=null) vars
ORDER
BY group_id
, id
) b
ON b.id = a.id
SET a.rank = b.rank;
此解决方案是由另一个用户abcdn实现的,请参见https://stackoverflow.com/a/32105418/3762855
SELECT a.id, a.group_id, (
SELECT count(*) from groups b where a.id >= b.id AND a.group_id = b.group_id
) AS row_number FROM groups a;
我发现了一种使用纯SQL且不使用自JOIN变量的方法来做到这一点:
UPDATE my_table
JOIN (
SELECT c.aid AS id, COUNT(*)-1 AS position_in_group
FROM (
SELECT a.id AS aid, b.id AS bid, a.group_id
FROM my_table AS a
JOIN my_table AS b ON (a.group_id=b.group_id AND a.id >= b.id)
) AS c
GROUP BY c.aid
) AS d ON my_table.id = d.id
SET my_table.position_in_group = d.position_in_group;
我将自己与表自身连接起来,以创建匹配对(同一组中的记录)而没有重复对。 然后,我只按左记录的ID对那些对进行分组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.