Postgres ENUM数据类型还是CHECK CONSTRAINT?

时间:2012-06-06 22:26:53

标签: postgresql postgresql-9.1

我一直在将MySQL数据库迁移到Pg(9.1),并且已经通过在Pg中创建新数据类型来模拟MySQL ENUM数据类型,然后将其用作列定义。我的问题 - 我可以使用CHECK CONSTRAINT而且会更好吗?实现MySQL ENUM类型以强制行中的特定值条目。可以用CHECK CONSTRAINT完成吗?如果是的话,会更好(或更糟)吗?

6 个答案:

答案 0 :(得分:63)

根据这里的评论和答案,以及一些初步的研究,我有以下摘要来提供Postgres-erati的评论。非常感谢您的意见。

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

  1. 枚举数据类型

    CREATE TYPE valid_colors AS ENUM ('red', 'green', 'blue');
    
    CREATE TABLE t (
        color VALID_COLORS
    );
    

    优点是类型可以定义一次,然后根据需要在尽可能多的表中重用。标准查询可以列出ENUM类型的所有值,并可用于创建应用程序表单小部件。

    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
    

    缺点是,ENUM类型存储在系统目录中,因此需要查询上述查询才能查看其定义。查看表定义时,这些值不明显。并且,由于ENUM类型实际上是与内置NUMERIC和TEXT数据类型分开的数据类型,因此常规数字和字符串运算符和函数不起作用。所以,不能像

    那样进行查询
    SELECT FROM t WHERE color LIKE 'bl%'; 
    
  2. 检查约束

    CREATE TABLE t (
        colors TEXT CHECK (colors IN ('red', 'green', 'blue'))
    );
    

    两个优点是,一个,“你看到的就是你得到的”,也就是说,列的有效值记录在表定义中,两个,所有本地字符串或数字运算符都有效。

  3. 外键

    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)
    );
    

    基本上与创建ENUM类型相同,除了本机数字或字符串运算符起作用,并且不必查询系统目录来发现有效值。需要联接才能将color_id与所需的文字值相关联。

答案 1 :(得分:11)

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

punkish's answer

调整架构
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
);

值在检查约束的情况下以内联方式存储,因此没有连接,但可以轻松添加新的有效值选项,并且可以通过ON UPDATE CASCADE更新现有值实例(例如,如果它是'决定"红色"实际应该是"红色",相应地更新valid_colors并且更改会自动传播。

答案 2 :(得分:3)

PostgreSQL有enum types,可以正常工作。我不知道枚举是否比约束“更好”,它们只是起作用。

答案 3 :(得分:1)

外键与检查约束的一个主要缺点是,任何报告或UI显示都必须执行连接以将ID解析为文本。

在一个小型系统中,这不是什么大不了的事,但如果你正在使用一个包含很多小型查找表的人力资源或类似系统,那么这可能是一个非常重要的事情,为了获取文本而发生了很多连接。

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

答案 4 :(得分:1)

从我的角度来看,给定相同的值

  1. 如果您要在多列中使用枚举,则枚举是一个更好的解决方案
  2. 如果您只想限制应用程序中一列的值,那么检查约束是一个更好的解决方案。

当然,还有很多其他参数可能会影响您的决策过程(通常,内置运算符不可用),但是我认为这两个参数是最普遍的。

答案 5 :(得分:0)

我希望有人能从PostgreSQL数据库方面得到一个好的答案,为什么一个人可能比另一个更好。

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

INSERT INTO table1 (colA, colB) VALUES('foo', 'bar'::myenum)

其中“myenum”是您在PostgreSQL中指定的枚举类型。

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

作为旁注,我注意到MySQL枚举不需要这种类型的转换,所以根据我的经验,这是PostgreSQL特有的。