Database design 如何处理数据库中没有枚举字段的枚举?

Database design 如何处理数据库中没有枚举字段的枚举?,database-design,enums,Database Design,Enums,如何在不支持枚举的数据库中实现枚举字段?i、 e.SQLite 需要使用field=?轻松搜索字段?因此,使用任何类型的数据序列化都是一个坏主意。我会使用varchar。这不是你的选择吗?你基本上有两个选择: 使用整数字段 使用varchar字段 我个人主张使用varchars,因为如果更改enum+字段,您不会破坏任何东西,但int也有一些优点,即性能数据的大小是一个明显的例子,为了限制可能的值,我将使用外键来保存枚举项的表 如果不想加入进行搜索,则将键设为varchar如果加入不是问题,则将

如何在不支持枚举的数据库中实现枚举字段?i、 e.SQLite


需要使用field=?轻松搜索字段?因此,使用任何类型的数据序列化都是一个坏主意。

我会使用varchar。这不是你的选择吗?

你基本上有两个选择:

使用整数字段

使用varchar字段


我个人主张使用varchars,因为如果更改enum+字段,您不会破坏任何东西,但int也有一些优点,即性能数据的大小是一个明显的例子,为了限制可能的值,我将使用外键来保存枚举项的表

如果不想加入进行搜索,则将键设为varchar如果加入不是问题,则将键设为INT,除非需要在该字段上搜索,否则不要加入

请注意,将枚举放在DB中会阻止编译时检查代码中的值,除非在代码中复制枚举。我发现这是一个很大的缺点。

我使用的方法是在查找表中使用外键。事实上,即使我使用了一个支持ENUM的数据库,比如MySQL,我也会使用它

为简单起见,我可以跳过查找表的永久id,只使用主表中所需的实际值作为查找表的主键。这样,您就不需要进行连接来获得值

CREATE TABLE BugStatus (
  status            VARCHAR(20) PRIMARY KEY
);

INSERT INTO BugStatus (status) VALUES ('NEW'), ('OPEN'), ('FIXED');

CREATE TABLE Bugs (
  bug_id            SERIAL PRIMARY KEY,
  summary           VARCHAR(80),
  ...
  status            VARCHAR(20) NOT NULL DEFAULT 'NEW',
  FOREIGN KEY (status) REFERENCES BugStatus(status)
);
诚然,存储字符串比MySQL的ENUM实现占用更多的空间,但除非所讨论的表有数百万行,否则这几乎不重要

查找表的其他优点是,您可以通过简单的插入或删除操作从列表中添加或删除值,而使用ENUM时,您必须使用ALTER table来重新定义列表

还可以尝试查询枚举中允许值的当前列表,例如,在用户界面中填充拾取列表。这真是个大麻烦!使用查找表,很容易:从BugStatus中选择status

此外,如果需要,您还可以向查找表中添加其他属性列,例如标记仅对管理员可用的选项。在枚举中,不能对条目进行注释;它们只是简单的值

除了查找表之外的另一个选项是使用检查约束,前提是数据库支持它们-MySQL在8.0.16版本之前不支持检查:

CREATE TABLE Bugs (
  bug_id            SERIAL PRIMARY KEY,
  summary           VARCHAR(80),
  ...
  status            VARCHAR(20) NOT NULL
    CHECK (status IN ('NEW', 'OPEN', 'FIXED'))
);
但是,这种使用检查约束的方法与枚举具有相同的缺点:在不更改表的情况下很难更改值列表,很难查询允许值列表,很难注释值


PS:SQL中的相等比较运算符是单=。double==在SQL中没有任何意义。

这就是我最近所做的

在hibernate映射的POJO中,我将成员的类型保留为字符串,并且在数据库中是VARCHAR

此设置程序采用枚举 还有另一个setter,它接受字符串-但这是私有的,或者您可以直接映射字段-如果您喜欢的话

现在,我正在使用字符串的事实从所有方面进行了封装。对于应用程序的其余部分,我的域对象使用enum。 就数据库而言,我使用的是字符串


如果我没有回答您的问题,我很抱歉。

如果您在hibernate中使用Spring JPA 2.1或更高版本,您可以实现自己的AttributeConverter并定义枚举如何映射到列值

@Converter(autoApply = true)
public class CategoryConverter implements AttributeConverter<Category, String> {
 
    @Override
    public String convertToDatabaseColumn(Category category) {
        if (category == null) {
            return null;
        }
        return category.getCode();
    }

    @Override
    public Category convertToEntityAttribute(String code) {
        if (code == null) {
            return null;
        }

        return Stream.of(Category.values())
          .filter(c -> c.getCode().equals(code))
          .findFirst()
          .orElseThrow(IllegalArgumentException::new);
    }
}

请参阅文章中的第4个解决方案。代码片段也在那里。

如果这是重复的,请小心。在我提问之前,我确实在StackOverflow上寻找答案。使用VARCHAR会导致数据非规范化。如果要更改枚举值的名称,则需要对整个表进行更新,而不仅仅是更改引用表中的一行。这很有意义。Ruby on Rails将允许与验证相同的行为作为奖励。感谢=vs.==这件事:我已经有一段时间没有直接使用SQL了。这是一个有点老的问题,但答案很棒。投票赞成。值得注意的是,只有当您愿意/有兴趣使用INNODB而不是MyISAM时,才可以在MySQL中使用它。@mOrloff:对,INNODB支持外键约束,但MyISAM不支持外键约束。使用InnoDB而不是MyISAM绝对是最佳实践,原因有很多,这只是其中之一。最好的答案,10年后,+1来自我