我很少看到野外使用的ENUM数据类型;开发人员几乎总是只使用如下所示的辅助表:
CREATE TABLE officer_ranks (
id int PRIMARY KEY
,title varchar NOT NULL UNIQUE);
INSERT INTO ranks VALUES (1,'2LT'),(2,'1LT'),(3,'CPT'),(4,'MAJ'),(5,'LTC'),(6,'COL'),(7,'BG'),(8,'MG'),(9,'LTG'),(10,'GEN');
CREATE TABLE officers (
solider_name varchar NOT NULL
,rank int NOT NULL REFERENCES officer_ranks(id) ON DELETE RESTRICT
,serial_num varchar PRIMARY KEY);
但是也可以使用用户定义的类型/ ENUM显示相同的内容:
CREATE TYPE officer_rank AS ENUM ('2LT', '1LT','CPT','MAJ','LTC','COL','BG','MG','LTG','GEN');
CREATE TABLE officers (
solider_name varchar NOT NULL
,rank officer_rank NOT NULL
,serial_num varchar PRIMARY KEY);
(使用PostgreSQL显示的示例,但其他RDBMS具有类似的语法)
我看到使用ENUM的最大缺点是在应用程序中更新更加困难。它也可能会使曾经习惯使用SQL DB的缺乏经验的开发人员感到困惑。
假设信息主要是静态的(工作日名称,月份名称,美国军队等级),使用ENUM有什么好处吗?
答案 0 :(得分:13)
使用PostgreSQL显示的示例,但其他RDBMS的语法类似
这是不正确的。它不是ISO / IEC / ANSI SQL要求,因此商业数据库不提供它(您应该提供Lookup表)。城镇的小端实施各种“额外”,但不实施城镇大端的更严格的要求或咕噜声。
我们也没有将ENUM作为DataType的一部分,这是荒谬的。
ENUM的第一个缺点是它不标准,因此不便携。
ENUM的第二大缺点是,数据库已关闭。可以在数据库上使用的数百个报表工具(独立于应用程序)找不到它们,因此无法预测名称/含义。如果您有一个普通的标准SQL查找表,则该问题将被消除。
第三,当您更改值时,您必须更改DDL。在普通标准SQL数据库中,只需在查找表中插入/更新/删除行。
最后,您无法轻易获得ENUM的内容列表;你可以使用Lookup表。更重要的是,您有一个向量来执行任何Dimension-Fact查询,无需从大型Fact表和GROUP BY中进行选择。
答案 1 :(得分:6)
我认为使用ENUMS没有任何优势。
它们更难维护,并且不提供任何具有正确外键的常规查找表不允许您执行的操作。
答案 2 :(得分:6)
一个小优势可能在于,您在创建ENUM时有一种UDT。用户定义的类型可以在许多其他数据库对象中正式重用,例如,在视图,其他表,其他类型,存储过程(在其他RDBMS中)等。
另一个优点是记录字段的允许值。例子:
可能是品味问题。我更喜欢ENUM这些类型的字段,而不是外键来查找这些简单概念的表。
另一个优点可能是当您在Java中使用代码生成或jOOQ之类的ORM时,您可以使用该ENUM从中生成Java枚举类,而不是加入查找表,或使用ENUM文字的ID
但事实上,只有少数RDBMS支持正式的ENUM类型。我只知道Postgres和MySQL。 Oracle或DB2没有它。
答案 3 :(得分:5)
使用像ENUM这样的东西的一个缺点是,如果数据表中没有这些值,则无法获取所有可用值的列表,除非您在某处对可用值列表进行硬编码。例如,如果在您的OFFICERS表中您没有碰巧有帖子上的MG,则无法知道排名是否存在。因此,当BG Blowhard被MG Marjorie-Banks解除时,你将无法进入新军官的级别 - 这是一种耻辱,因为他是现代少将的模范。 :-)当陆军将军(五星将军)出现时会发生什么?
对于不会改变的简单类型,我已经成功使用了域。例如,在我的一个数据库中,我有一个yes_no_domain定义如下:
CREATE DOMAIN yes_no_dom
AS character(1)
DEFAULT 'N'::bpchar
NOT NULL
CONSTRAINT yes_no_dom_check
CHECK ((VALUE = ANY (ARRAY['Y'::bpchar, 'N'::bpchar])));
分享并享受。
答案 4 :(得分:2)
一般来说,对于没有太大变化的东西,枚举更好,并且它使用的资源稍少,因为没有FK检查或者在插入等上执行的任何东西。
使用查找表更优雅或更传统,添加和删除选项比枚举更容易。比枚举更容易批量更改值。
答案 5 :(得分:2)
优点:
存储过程的类型安全性:如果无法将参数强制转换为类型,则会引发类型错误。例如:select court_martial('3LT')
会自动引发类型错误。
自定义联盟顺序:在您的示例中,可以对没有排名ID的人员进行排序。
答案 6 :(得分:2)
ENUMS 非常非常有用!你只需要知道如何使用它们:
因此,如果您有要使用的固定字符串值列表,则与查找表相比,ENUM 是更好的解决方案。假设您需要列出产品中的氨基酸及其各自的重量。今天有~20种氨基酸。如果您要存储他们的全名,则每次需要更多空间,然后是 2 个字节。另一种选择是使用人工键并链接到外部表。但是国外的 Table 会是什么样子呢?它是否有 2 列:ID 和氨基酸名称?你每次都会加入那张桌子吗?如果您的主表有超过 40 个这样的字段怎么办?查询该表将涉及 >40 个联接。
如果您的数据库包含 1600 个表,其中 400 个是仅替换 ENUM 的查找表,您的开发人员将浪费大量时间浏览它们(除了 JOIN)。是的,您可以使用前缀、模式等......但为什么不直接踢出这些表呢?
ENUMS 是枚举列表/有序。这意味着,如果您的值是有序的,您实际上省去了维护 3 列查找表的麻烦。
问题是:那我为什么需要查找表? 嗯,答案很简单:
现在有趣的是: 查找表和 ENUMS 不能完全相互替代!!!! 如果您有一个列表,其中 PK 是单列自然键。列表可以增长或值可以更改其名称(出于某种原因),然后您可以定义一个 ENUM 并将其用于两者:查找中的 PK 和主表中的 FK!
示例优势: 您必须更改查找键的名称。如果不使用 ENUM,DBMS 将不得不将更改级联到所有表,您在其中使用此值而不仅仅是您的查找表。如果您使用的是ENUM,那么您只需更改ENUM 的值,数据不会发生任何变化。
答案 7 :(得分:0)
嗯,你没有看到,因为通常开发人员在编程语言(如Java)中使用枚举,并且在数据库设计中没有对应物。
在数据库中,这样的枚举通常是文本或整数字段,没有约束。数据库枚举不会被翻译成Java / C#/ etc。枚举,所以开发人员认为没有收获。
有许多非常好的数据库功能很少使用,因为大多数ORM工具都太原始而无法支持它们。