【问题标题】:Rename enum item in PostgreSQL重命名 PostgreSQL 中的枚举项
【发布时间】:2025-11-26 19:45:02
【问题描述】:

我想在 PostgreSQL 9.1.5 中更改枚举类型中项目的名称。

这是类型的创建语句:

CREATE TYPE import_action AS ENUM
('Ignored',
'Inserted',
'Updated',
'Task created');

我只想将“创建的任务”更改为“已中止”。从documentation 看来,以下应该可以工作:

ALTER TYPE import_action
RENAME ATTRIBUTE "Task created" TO "Aborted"; 

但是,我收到一条消息:

********** Error **********

ERROR: relation "import_action" does not exist
SQL state: 42P01

但是,它显然确实存在。

该类型当前被多个表使用。

我认为一定没有办法做到这一点。我已经尝试了 pgAdminIII 中类型的对话框,但是我看不到在那里重命名它。 (所以,要么强烈暗示我做不到,要么 - 我希望 - 一个小的疏忽是创建该对话框的开发人员)

如果我不能在一个声明中做到这一点?那我需要做什么?我是否必须编写脚本来添加项目,将所有记录更新为新值,然后删除旧项目?那还能用吗?

这似乎应该是一件简单的事情。据我了解,记录只是存储对类型和项目的引用。我认为它们实际上并没有存储我给它的文本值。但是,也许我在这里也错了。

【问题讨论】:

    标签: postgresql postgresql-9.1


    【解决方案1】:

    在 PostgreSQL 版本 10 中,将枚举标签 has been added 重命名为 ALTER TYPE 语法的一部分的功能:

    ALTER TYPE name RENAME VALUE existing_enum_value TO new_enum_value
    

    【讨论】:

      【解决方案2】:

      更新:对于 PostgreSQL 版本 10 或更高版本,请参阅投票最多的答案。

      枚举值的名称称为标签,属性完全不同。

      不幸的是,更改枚举标签并不简单,您必须对系统目录进行处理: http://www.postgresql.org/docs/9.1/static/catalog-pg-enum.html

      UPDATE pg_enum SET enumlabel = 'Aborted' 
      WHERE enumlabel = 'Task created' AND enumtypid = (
        SELECT oid FROM pg_type WHERE typname = 'import_action'
      )
      

      【讨论】:

      • 感谢您的回复...我想知道这是一个好(或坏)的想法。看起来如果这是一个安全的操作,他们将有办法通过 ALTER TYPE stmt 或通过 pgAdminIII 对话框来做到这一点。也就是说,(对我而言)您似乎应该能够做到这一点。我认为这只是一个标签。还有其他的cmets吗?
      • @DavidS 我不认为它不安全。更多的是 PostgreSQL 开发人员没有添加这样的功能。 (添加值的能力,就像在 Catcall 的回答中一样,只是在 9.1 中才添加的。)
      • @Catcall Footgun 评论指的是删除一个值,但无论如何,我不认为有 6 年历史的评论反对某项功能(自该讨论以来已部分实施)是相关的。
      • @Catcall "添加、删除或重命名" 包括添加;并且您在下面的回答描述了如何将元素添加到枚举类型,那么您怎么能说它尚未实现? Andrew 称它为footgun 的原因是,“我们必须检查每一行以确保我们没有孤立某个值”,这显然是指删除一个值。
      • @Catcall 我知道。您在上一条评论中写道,设计师(六年前)反对添加、删除或重命名。显然,他们不再反对添加,因为他们确实已经实现了。由于他们不再反对添加,因此没有理由相信他们会继续反对重命名,除非他们最近明确表示。而且,这是第三次,很明显,footgun 评论是关于删除的,因为对这个问题的解释是“孤立的值”。
      【解决方案3】:

      接受的答案中的查询不考虑架构名称。这是基于http://tech.valgog.com/2010/08/alter-enum-in-postgresql.html 的更安全(更简单)的方法

      UPDATE pg_catalog.pg_enum
      SET enumlabel = 'NEW_LABEL'
      WHERE enumtypid = 'SCHEMA_NAME.ENUM_NAME'::regtype::oid AND enumlabel = 'OLD_LABEL'
      RETURNING enumlabel;
      

      请注意,这需要“rolcatupdate”(直接更新目录)权限 - 即使是超级用户也是不够的。

      从 PostgreSQL 9.3 开始,似乎直接更新目录仍然是唯一的方法。

      【讨论】:

        【解决方案4】:

        类型、属性和值之间存在差异。你可以像这样创建一个枚举。

        CREATE TYPE import_action AS ENUM
        ('Ignored',
        'Inserted',
        'Updated',
        'Task created');
        

        完成后,您可以将添加到枚举中。

        ALTER TYPE import_action 
        ADD VALUE 'Aborted';
        

        但语法图不显示任何对删除或重命名 的支持。您正在查看的语法是重命名属性的语法,而不是值。

        虽然这种设计可能令人惊讶,但它也是经过深思熟虑的。来自pgsql-hackers mailing list

        如果需要修改使用的值或者想知道整数是什么 是,改用查找表。枚举是错误的抽象 你。

        【讨论】:

        • 为什么这个答案被否决了?这是枚举旨在工作的唯一方式。我不喜欢手动修改系统目录。而且,需要明确的是,枚举是完全不必要的(可以用关系工具代替,如表和 FK)。
        • 它没有回答问题。
        • 实际上邮件列表中的引用有点脱离上下文。它指的是想要访问枚举的整数表示的用户。至于更改标签,邮件列表条目说:“支持 ALTER TYPE 以允许添加/修改值等。暂时你只需要创建一个新类型,执行一堆 ALTER TABLE 命令,删除旧的如果您想恢复旧名称,请键入并重命名新名称。”