SQL:ENUM与一对多关系的优势?

时间:2010-11-27 19:30:09

标签: sql database-design postgresql

我很少看到野外使用的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有什么好处吗?

8 个答案:

答案 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中)等。

另一个优点是记录字段的允许值。例子:

  • 是/否字段
  • 男/女场
  • mr / mrs / ms / dr field

可能是品味问题。我更喜欢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 非常非常有用!你只需要知道如何使用它们:

  1. 一个 ENUM 仅使用 2 个字节的存储空间。
  2. 无需额外约束(替代 FK)。
  3. 与 FK 中的自然值相比,值的变化更便宜。
  4. 无需额外的 JOIN
  5. ENUM 已排序,例如您可以比较周一 < 周五,或 1 月 < 六月或项目启动 < 工资单。

因此,如果您有要使用的固定字符串值列表,则与查找表相比,ENUM 是更好的解决方案。假设您需要列出产品中的氨基酸及其各自的重量。今天有~20种氨基酸。如果您要存储他们的全名,则每次需要更多空间,然后是 2 个字节。另一种选择是使用人工键并链接到外部表。但是国外的 Table 会是什么样子呢?它是否有 2 列:ID 和氨基酸名称?你每次都会加入那张桌子吗?如果您的主表有超过 40 个这样的字段怎么办?查询该表将涉及 >40 个联接。

如果您的数据库包含 1600 个表,其中 400 个是仅替换 ENUM 的查找表,您的开发人员将浪费大量时间浏览它们(除了 JOIN)。是的,您可以使用前缀、模式等......但为什么不直接踢出这些表呢?

ENUMS 是枚举列表/有序。这意味着,如果您的值是有序的,您实际上省去了维护 3 列查找表的麻烦。

问题是:那我为什么需要查找表? 嗯,答案很简单:

  1. 当你的价值观经常改变时
  2. 当您需要存储更多附加属性时 --> 查找表对应于完整的数据对象,而不是查找列表。
  3. 当你需要它的时候又快又脏

现在有趣的是: 查找表和 ENUMS 不能完全相互替代!!!! 如果您有一个列表,其中 PK 是单列自然键。列表可以增长或值可以更改其名称(出于某种原因),然后您可以定义一个 ENUM 并将其用于两者:查找中的 PK 和主表中的 FK!

示例优势: 您必须更改查找键的名称。如果不使用 ENUM,DBMS 将不得不将更改级联到所有表,您在其中使用此值而不仅仅是您的查找表。如果您使用的是ENUM,那么您只需更改ENUM 的值,数据不会发生任何变化。

答案 7 :(得分:0)

嗯,你没有看到,因为通常开发人员在编程语言(如Java)中使用枚举,并且在数据库设计中没有对应物。

在数据库中,这样的枚举通常是文本或整数字段,没有约束。数据库枚举不会被翻译成Java / C#/ etc。枚举,所以开发人员认为没有收获。

有许多非常好的数据库功能很少使用,因为大多数ORM工具都太原始而无法支持它们。