问题
I have a table called medias
where I've just recently added a new column to called sort_order
of type Int
.
The row values will not be unique to the entire table, but to their own respective owner_user_id
fields. Regardless, I don't even care about the uniqueness of them tbh.
The point of all this is to allow users to set the sort order of the photos they upload (up to 10, and they can drag and re-order, etc). When the user "deletes" a photo, I don't remove the record, I simply set a visible
field to false
on that row.
Aaaanyway, I'm introducing a migration that adds sort_order
(they used to not be able to order the photos, they would just be sorted according to order by created_at asc
).
Since adding the new field, I've made the new sort_order
have a default value of 10
(so that it's backwards compatible for folks who haven't updated the application).
I was able to come up with this query:
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;
This spits out something that looks like the following:
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
at this point all i really want to do is set that sort_order
to that rank()
. Any thoughts on how to do this?
回答1:
As you do not have a unique key, use 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;
Note, row_number()
may be better than rank()
as the first never gives duplicates.
回答2:
You can use a join
, but you need a unique id. Let me assume that you have one:
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;
Basically, you are doing the calculation in a subquery and then joining the result back to the table for the update.
来源:https://stackoverflow.com/questions/40296265/postgres-update-using-rank-window-function