2016-10-28 2 views
2

У меня есть таблица с именем medias, где я недавно добавил новый столбец для вызова sort_order типа Int.Postgres UPDATE с использованием функции ранга окна

Значения строк не будут уникальными для всей таблицы, но для их соответствующих полей owner_user_id. Несмотря ни на что, я даже не забочусь об уникальности их tbh.

Цель всего этого - позволить пользователям устанавливать порядок сортировки загружаемых фотографий (до 10, и они могут перетаскивать и переупорядочивать и т. Д.). Когда пользователь «удаляет» фотографию, я не удаляю запись, я просто устанавливаю поле visible на false в этой строке.

Aaaanyway, я представляю миграцию, которая добавляет sort_order (они раньше не могли заказывать фотографии, они просто сортировались бы в соответствии с order by created_at asc).

С момента добавления нового поля, я сделал новое sort_order значением по умолчанию 10 (так, чтобы оно было обратным для людей, которые не обновили приложение).

я был в состоянии придумать с этим запросом:

select 
    owner_user_id, 
    sort_order, rank() over (PARTITION BY owner_user_id ORDER BY sort_order asc, created_at asc) as new_sort_order 
from medias 
where visible=true 
order by sort_order asc, created_at asc; 

Это выплевывает то, что выглядит следующим образом:

owner_user_id | sort_order | new_sort_order 
---------------+------------+--------------- 
      76 |   10 |  1 
      76 |   10 |  2 
      76 |   10 |  3 
      76 |   10 |  4 
      76 |   10 |  5 
      9 |   10 |  1 
      9 |   10 |  2 
      9 |   10 |  3 
      9 |   10 |  4 
      9 |   10 |  5 
      79 |   10 |  1 
      79 |   10 |  2 
      87 |   10 |  1 
      87 |   10 |  2 
      87 |   10 |  3 
      85 |   10 |  1 
      90 |   10 |  1 
      90 |   10 |  2 
      90 |   10 |  3 

в этот момент все, что я действительно хочу сделать, это установить, что sort_order с этим rank(). Любые мысли о том, как это сделать?

ответ

4

Как вы не имеете уникальный ключ, используйте ctid:

update medias m 
    set sort_order = new_sort_order 
    from (
     select 
      ctid, 
      owner_user_id, 
      sort_order, 
      row_number() over w as new_sort_order 
     from medias 
     where visible 
     window w as (partition by owner_user_id order by sort_order asc, created_at asc) 
    ) s 
    where m.ctid = s.ctid; 

Примечание, row_number() может быть лучше, чем rank() как первое никогда не дает дубликаты.

2

Вы можете использовать join, но вам нужен уникальный идентификатор. Позвольте мне предположить, что у вас есть один:

update medias m 
    set sort_order = new_sort_order 
    from (select m.*, 
       rank() over (PARTITION BY owner_user_id ORDER BY sort_order asc, created_at asc) as new_sort_order 
      from medias m 
      where visible = true 
     ) mm 
    where m.id = mm.id; 

В принципе, вы делаете расчет в подзапрос, а затем присоединение результат обратно к столу для обновления.

Смежные вопросы