繁体   English   中英

如何在SQL中设置记录相对于组的位置?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM