我一直在将MySQL数据库迁移到Pg(9.1),并且已经通过在Pg中创建新数据类型来模拟MySQL ENUM数据类型,然后将其用作列定义。我的问题 - 我可以使用CHECK CONSTRAINT而且会更好吗?实现MySQL ENUM类型以强制行中的特定值条目。可以用CHECK CONSTRAINT完成吗?如果是的话,会更好(或更糟)吗?
答案 0 :(得分:63)
根据这里的评论和答案,以及一些初步的研究,我有以下摘要来提供Postgres-erati的评论。非常感谢您的意见。
有三种方法可以限制Postgres数据库表列中的条目。考虑一个表来存储“颜色”,你只想要“红色”,“绿色”或“蓝色”作为有效条目。
枚举数据类型
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%';
检查约束
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)
);
基本上与创建ENUM类型相同,除了本机数字或字符串运算符起作用,并且不必查询系统目录来发现有效值。需要联接才能将color_id
与所需的文字值相关联。
答案 1 :(得分:11)
正如其他答案所指出的,检查约束具有灵活性问题,但是在整数id上设置外键需要在查找期间加入。为什么不在参考表中使用允许的值作为自然键?
调整架构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)
从我的角度来看,给定相同的值
当然,还有很多其他参数可能会影响您的决策过程(通常,内置运算符不可用),但是我认为这两个参数是最普遍的。
答案 5 :(得分:0)
我希望有人能从PostgreSQL数据库方面得到一个好的答案,为什么一个人可能比另一个更好。
从软件开发人员的角度来看,我稍微倾向于使用检查约束,因为PostgreSQL枚举需要在SQL中执行更新/插入,例如:
INSERT INTO table1 (colA, colB) VALUES('foo', 'bar'::myenum)
其中“myenum”是您在PostgreSQL中指定的枚举类型。
这肯定会使SQL不可移植(这对大多数人来说可能不是什么大问题),但也是开发应用程序时必须处理的另一件事,所以我更喜欢使用VARCHAR(或其他典型的原语) )有检查约束。
作为旁注,我注意到MySQL枚举不需要这种类型的转换,所以根据我的经验,这是PostgreSQL特有的。