Postgresql Postgres枚举数据类型还是检查约束?

Postgresql Postgres枚举数据类型还是检查约束?,postgresql,postgresql-9.1,Postgresql,Postgresql 9.1,我一直在将MySQL数据库迁移到Pg(9.1),并一直在模拟MySQL枚举数据类型,方法是在Pg中创建一个新的数据类型,然后将其用作列定义。我的问题是,我是否可以使用CHECK约束来代替?MySQL枚举类型的实现是为了强制行中的特定值条目。这可以通过检查约束来完成吗?而且,如果是的话,它会更好(还是更糟)?PostgreSQL已经发挥了应有的作用。我不知道枚举是否比约束“更好”,它们只是都起作用。我希望有人能从PostgreSQL数据库方面给出一个好的答案,解释为什么一个比另一个更好 从软件开发

我一直在将MySQL数据库迁移到Pg(9.1),并一直在模拟MySQL枚举数据类型,方法是在Pg中创建一个新的数据类型,然后将其用作列定义。我的问题是,我是否可以使用CHECK约束来代替?MySQL枚举类型的实现是为了强制行中的特定值条目。这可以通过检查约束来完成吗?而且,如果是的话,它会更好(还是更糟)?

PostgreSQL已经发挥了应有的作用。我不知道枚举是否比约束“更好”,它们只是都起作用。

我希望有人能从PostgreSQL数据库方面给出一个好的答案,解释为什么一个比另一个更好

从软件开发人员的角度来看,我稍微倾向于使用检查约束,因为PostgreSQL枚举需要在SQL中进行强制转换来执行更新/插入,例如:

INSERT INTO table1 (colA, colB) VALUES('foo', 'bar'::myenum)
其中“myenum”是您在PostgreSQL中指定的枚举类型

这当然会使SQL不可移植(这对大多数人来说可能不是什么大问题),但这也是开发应用程序时必须处理的另一件事,因此我更喜欢使用带有检查约束的varchar(或其他典型原语)


顺便说一句,我注意到MySQL枚举不需要这种类型的强制转换,因此根据我的经验,这是PostgreSQL所特有的。

基于这里的评论和答案,以及一些初步的研究,我有以下总结供Postgres erati的评论。非常感谢你的意见

有三种方法可以限制Postgres数据库表列中的条目。考虑一个存储“颜色”的表,其中只希望“红色”、“绿色”或“蓝色”为有效条目。

  • 枚举数据类型

    CREATE TYPE valid_colors AS ENUM ('red', 'green', 'blue');
    
    CREATE TABLE t (
        color VALID_COLORS
    );
    
    优点是该类型可以定义一次,然后根据需要在尽可能多的表中重用。标准查询可以列出枚举类型的所有值,并可用于制作应用程序表单小部件

    SELECT  n.nspname AS enum_schema,  
            t.typname AS enum_name,  
            e.enumlabel AS enum_value
    FROM    pg_type t JOIN 
            pg_enum e ON t.oid = e.enumtypid JOIN 
            pg_catalog.pg_namespace n ON n.oid = t.typnamespace
    WHERE   t.typname = 'valid_colors'
    
     enum_schema | enum_name     | enum_value 
    -------------+---------------+------------
     public      | valid_colors  | red
     public      | valid_colors  | green
     public      | valid_colors  | blue
    
    缺点是,枚举类型存储在系统目录中,因此需要如上所述的查询来查看其定义。查看表定义时,这些值不明显。而且,由于枚举类型实际上是独立于内置数字和文本数据类型的数据类型,因此常规的数字和字符串运算符和函数不适用于它。所以,我们不能做这样的查询

    SELECT FROM t WHERE color LIKE 'bl%'; 
    
  • 检查约束

    CREATE TABLE t (
        colors TEXT CHECK (colors IN ('red', 'green', 'blue'))
    );
    
    两个优点是,第一,“所见即所得”,即列的有效值记录在表定义中,第二,所有本机字符串或数字运算符都有效

  • 外键

    CREATE TABLE valid_colors (
        id SERIAL PRIMARY KEY NOT NULL,
        color TEXT
    );
    
    INSERT INTO valid_colors (color) VALUES 
        ('red'),
        ('green'),
        ('blue');
    
    CREATE TABLE t (
        color_id INTEGER REFERENCES valid_colors (id)
    );
    
    本质上与创建枚举类型相同,只是本机数字或字符串运算符可以工作,并且不必查询系统目录来发现有效值。需要联接才能将
    颜色\u id
    链接到所需的文本值


  • 外键与检查约束的最大缺点之一是,任何报告或UI显示都必须执行联接才能将id解析为文本

    在一个小系统中,这不是什么大不了的事,但是如果你在一个HR或类似的系统上工作,有很多小的查找表,那么这可能是一个很大的问题,因为很多连接只是为了得到文本


    我的建议是,如果值很少且很少更改,则对文本字段使用约束,否则对整数id字段使用查找表。

    正如其他答案所指出的,检查约束有灵活性问题,但在整数id上设置外键需要在查找期间加入。为什么不在引用表中使用允许的值作为自然键呢

    要从中调整架构,请执行以下操作:


    值与check constraint的情况一样以内联方式存储,因此没有联接,但是可以轻松添加新的有效值选项,并且可以通过更新级联上的
    更新现有值实例(例如,如果确定“红色”实际上应该是“红色”),相应地更新有效的颜色,更改会自动传播。

    在我看来,给定相同的值集

  • 如果将枚举用于多列,则它是一个更好的解决方案
  • 如果希望在应用程序中仅限制一列的值,则检查约束是更好的解决方案

  • 当然,在您的决策过程中可能会出现大量其他参数(通常情况下,内置运算符不可用),但我认为这两个是最常见的参数。

    我个人更喜欢使用检查约束(甚至是带有FK约束的查找表)来处理这类问题。这使得以后更改它们更容易。为什么不使用PG的枚举类型呢?为什么您认为需要“模拟”枚举类型?枚举类型的另一个问题是字符串运算符不起作用。例如,如果我有一个带有文本选项的枚举字段,我就不能对其使用LIKE。另一方面,在检查约束下,文本仍将被视为文本。对于PostgreSQL,再次同意。我也看到了这一点,应该在回答时考虑到这一点。我只是在MySQL中进行了测试,MySQL并没有施加这种限制——您可以将LIKE与枚举一起使用。因此,我对PostgreSQL的投票是为了避免使用枚举,除非有其他我不知道的好理由使用它们。最初的声明似乎不再有效:当前postgres文档中没有提到
    ::myenum
    后缀:另外,还有另一个表和一个外键,您可以将颜色管理委托给普通用户,而不让他们更改表格。从抽象的角度来看,我看不出1)和3)之间有什么区别。。想法是一样的,不同的是PG创建了REF表。无论哪种方式,我都可以轻松地从该REF表中选择/查看/更改有效选项。别忘了,动态创建一个有效选项列表是很容易的
    CREATE TABLE valid_colors (
        color TEXT PRIMARY KEY
    );
    
    INSERT INTO valid_colors (color) VALUES 
        ('red'),
        ('green'),
        ('blue');
    
    CREATE TABLE t (
        color TEXT REFERENCES valid_colors (color) ON UPDATE CASCADE
    );