[英]How do I set the record's position relative to a group in SQL?
I have a series of records that can be grouped by a group_id
我有一系列可以按
group_id
分组的group_id
Example records: 记录示例:
╭───╥──────────┬───────────────────╮
│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 │
└───╨──────────┴───────────────────┘
I want to set the position_in_group
for each record. 我想为每个记录设置
position_in_group
。 It is the position of the record inside the group if I GROUP BY group_id
. 如果I
GROUP BY group_id
,则它是记录在组内的位置。
For example: In the group with id 1, the record with id=2 is the first, so its position_in_group
would be 1. 例如:在id为1的组中,id为2的记录是第一条记录,因此其
position_in_group
为1。
The final table would be: 决赛桌将是:
╭───╥──────────┬───────────────────╮
│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 │
└───╨──────────┴───────────────────┘
Is there any way I can do this in a SQL query? 有什么办法可以在SQL查询中执行此操作?
One method is to use variables. 一种方法是使用变量。 A bit challenging in MySQL, but it can look like this:
在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;
Note: You need to initialize the variables separately from the update
statement, because MySQL does not support joins and order by in the same update
statement. 注意:您需要与
update
语句分开分别初始化变量,因为MySQL不支持在同一update
语句中进行联接和排序。
There's no need to store this data... 无需存储此数据...
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;
...but if you really want to... ...但是如果您真的想...
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;
this solution was implemented by another user abcdn see https://stackoverflow.com/a/32105418/3762855 此解决方案是由另一个用户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;
I found out a way to do this with pure SQL and without variables with a self JOIN: 我发现了一种使用纯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;
I self join the table with itself to create matching pairs (records in the same group) without duplicate pairs. 我将自己与表自身连接起来,以创建匹配对(同一组中的记录)而没有重复对。 Then I just count those pairs grouping by the id of the left record.
然后,我只按左记录的ID对那些对进行分组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.