The following code changes the order of categories to be alphanumeric using SQL.
Preconditions.
Postgres backend
UPDATE categories
SET POSITION = subquery.position
FROM (
SELECT POSITION
, CASE WHEN category_id = 0 THEN parent_category_id ELSE category_id END category_id
, CASE WHEN category_id = 0 THEN parent_category_name ELSE category_name END category_name
FROM (
SELECT ROW_NUMBER - 1 AS POSITION
, parent_category_id
, parent_category_name
, category_id
, category_name
FROM ( SELECT row_number() OVER ( ORDER BY parent_category_name, category_name )
, * FROM (
SELECT * FROM (
SELECT id parent_category_id
, name parent_category_name
, 0 category_id
, cast('' AS text) category_name
FROM categories
WHERE parent_category_id IS NULL ORDER BY name
) parent_categories
UNION
(
SELECT child.parent_category_id
, parent.name parent_category_name
, child.id category_id
, child.name category_name
FROM categories child
INNER JOIN categories parent
ON child.parent_category_id = parent.id
WHERE child.parent_category_id IS NOT NULL ORDER BY child.name
)
) parents_with_children
ORDER BY parent_category_name, category_name
) ordered_parents_with_children
ORDER BY ROW_NUMBER
) category_positions_sorted_alphabetically
) subquery
WHERE id = subquery.category_id ;
I ran the code by starting up a psql session.
/var/discourse/launcher enter app
su postgres
psql discourse
and then executing the SQL.
Running from rails console.
ActiveRecord::Base.connection.execute("UPDATE categories SET POSITION = subquery.position FROM ( SELECT POSITION , CASE WHEN category_id = 0 THEN parent_category_id ELSE category_id END category_id , CASE WHEN category_id = 0 THEN parent_category_name ELSE category_name END category_name FROM ( SELECT ROW_NUMBER - 1 AS POSITION , parent_category_id , parent_category_name , category_id , category_name FROM ( SELECT row_number() OVER ( ORDER BY parent_category_name, category_name ) , * FROM ( SELECT * FROM ( SELECT id parent_category_id , name parent_category_name , 0 category_id , cast('' AS text) category_name FROM categories WHERE parent_category_id IS NULL ORDER BY name ) parent_categories UNION ( SELECT child.parent_category_id , parent.name parent_category_name , child.id category_id , child.name category_name FROM categories child INNER JOIN categories parent ON child.parent_category_id = parent.id WHERE child.parent_category_id IS NOT NULL ORDER BY child.name ) ) parents_with_children ORDER BY parent_category_name, category_name ) ordered_parents_with_children ORDER BY ROW_NUMBER ) category_positions_sorted_alphabetically ) subquery WHERE id = subquery.category_id")