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