2016-10-28 12 views
2

私はmediasというテーブルを持っています。ここでは、最近Intというsort_orderという新しい列を追加しました。ランクウィンドウ関数を使用したPostgres UPDATE

行の値は、テーブル全体ではなく、それぞれのowner_user_idフィールドに固有の値になります。それにもかかわらず、私はそれらの一意性を気にしない。

これは、ユーザーがアップロードした写真のソート順を設定できるようにすることです(最大10個までドラッグアンドリオーダーなどが可能です)。ユーザーが写真を「削除」したときにレコードを削除しない場合、その行のvisibleフィールドをfalseに設定するだけです。

私は、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を使用できますが、一意のIDが必要です。

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; 

基本的に、サブクエリで計算を行い、その結果を更新のためにテーブルに戻しています。

関連する問題