SQL を使用したカテゴリの順序付け

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")
「いいね!」 2

I’ve not tested this recently but here’s at least a hint for how to alpha-sort categories at the rails console:

# alpha sort all categories matching search and their sub-categories

  def sort_matching_categories_and_subcategories(search)
    categories = Category.where("name like ?", search)
    position = 100
    categories.order(:name).each do |cat|
      position += 5
      cat.position = position
      cat.save!()
      c_position = 0
      children = Category.where(:parent_category_id=>cat.id)
      children.order(:name).each do |c|
        c_position += 5
        c.position = c_position
        c.save!()
      end
    end
  end


 # alpha sort subcategories of a single category matching search
def sort_matching_subcategories(search)
  categories = Category.where("name like ?", search)
  if categories.count > 1
    puts "Found more than one category"
  end
  categories.order(:name).each do |cat|
    c_position = 5
    children = Category.where(:parent_category_id=>cat.id)
    children.order(:name).each do |c|
      c_position += 5
      c.position = c_position
      c.save!()
    end
  end
end
「いいね!」 1

Thanks @pfaffman

Based on your ruby code I came up with

def sort_categories_by_name(skip=0)
  
  parents = Category.where("parent_category_id is null")
  position = 0
  parents.order(:name).each do |parent|
    parent.position = position
    parent.save!()
    position += (1+skip)
    children = Category.where(:parent_category_id=>parent.id)
    children.order(:name).each do |child|
      child.position = position
      child.save!()
      position += (1+skip)  
    end
  end
  
  position += -(1+skip)  
  return position
  
end

sort_categories_by_name
「いいね!」 1

こんにちは。初めて利用します。
この投稿で、GUI のオプションを使ってカテゴリをアルファベット順に設定できないことが明確にされているでしょうか?

ありがとうございます。

ある程度は可能です。固定順序で配置するための設定があります。まずシステム設定で「fixed」などで検索して設定し、その後、UX(ユーザーインターフェース)から操作できるはずです。

十数個程度であれば、UX で手動で整理してもそれほど大変ではありません(このインターフェースは以前から問題があり、現在の動作については確実な情報が得られていないため、内容が正確でない可能性もあります)。しかし、数百個あり、変更がない場合は、以前にコンソールから実行してソートするスクリプトを作成したことがあります。さらに、多数あり、頻繁に変更しながら常にソート状態を維持したい場合は、プラグインが必要になります。

ありがとうございます。私は「discourse」Freephone フォーラムのユーザーに過ぎず、モデレーターにリストの順序を変更できるか尋ねました。しかし、最初の回答は、このフォーラムで方法を調べてほしいというものでした。つまり、簡単に利用可能なオプションではないのだと思います。

再度、ありがとうございます。

カテゴリが数十にも及ばない限り、大した問題ではありません。また、設定を自分で確認したり、ここで自分で質問したりする代わりにあなたをここに送ってきたのであれば、彼らは単に面倒だと思っているだけです。

改めてありがとうございます。

モデレーターにはバックエンドへのアクセス権がないようですが、これは不可欠な機能のようです。

では、自分でダウンロードしてホストしてみようと思います。そうすれば、やりたいことをどう実現すればよいか分かり、その情報を共有できるはずです :slight_smile: この問題を処理できる管理者が必ずいるはずです。

「いいね!」 1

どうやら、その方法をわかっているモデレーターがいるようです。後で連絡しますね。ハンバーガーメニューから可能だとのことです。