2016-06-27 2 views
0

У меня есть ряд записей, которые могут быть группируются по group_idКак установить позицию записи относительно группы в SQL?

Пример записи:

╭───╥──────────┬───────────────────╮ 
│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 для каждой записи. Это позиция записи внутри группы, если я GROUP BY group_id.

Например: В группе с идентификатором 1, запись с идентификатором = 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   │ 
└───╨──────────┴───────────────────┘ 

Is Есть ли способ сделать это в SQL-запросе?

+2

Это будет сделано с использованием 'row_number() over (partition by group_id order by id)' в oracle и sqlserver. Проверьте здесь параметры эквивалента mysql: http://stackoverflow.com/q/1895110/6205293 – mo2

+0

Да, запрос с переменными (@) ... кто-то ударил. – Drew

ответ

0

Я нашел способ сделать это с использованием чистого 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 левой записи.

1

Один из способов - использовать переменные. Немного оспаривание в 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 заявления.

0

Там нет необходимости хранить эти данные ...

SELECT id 
    , group_id 
    , rank 
    FROM 
    (SELECT id 
      , group_id 
      , CASE WHEN group_id = @prev THEN @i:[email protected]+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:[email protected]+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; 
0

это решение было реализовано другим пользователем 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; 
Смежные вопросы