我有一个创建为

CREATE TABLE `sklllevel` (
  `Name` varchar(20) NOT NULL,
  `level` enum('No Experience','Beginner','Expert','Advisor') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

有价值的
INSERT INTO test.sklllevel (name,level) values ('No Experience','No Experience'),('Beginner','Beginner'),('Expert','Expert'),('Advisor','Advisor');

我想在另一个创建为的表中引用SkillLevel.Level withtestSkill.tkSkill
CREATE TABLE `testskill` (
  `pkid` int(11) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  `tkSkill` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`pkid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

要设置外键,是否需要tkSkill作为具有相同值集的枚举?这里最好的做法是什么?

最佳答案

简而言之:枚举是以数字形式存储的,所以从技术上讲,可以用tkSkill作为tinyint来连接它们。
要将它用作外键,您确实需要同时拥有tkSkilllevel才能成为同一个枚举-但是您需要level成为unique列才能成为外键,因此将unique添加到它中(确切地说:对于InnoDB,如果您手动创建索引,您可以拥有非唯一的外键,但非唯一的外键通常是一个坏主意)。但是您应该考虑一下sklllevel中的键应该是什么,因为现在看来您似乎希望Name是键。
独立于将其作为键,您应该将tkSkill定义为(相同的)枚举,以确保它们的含义相同,如果您在某一点上想要更改枚举(这是个坏主意!)例如,添加另一个技能级别;或者如果您想“读取”(直接理解)从表testskill中直接选择而不需要加入sklllevel时的值;如果您想通过使用它们的枚举namoe(例如,“Expert”而不是3,但您可以同时使用这两个)将值插入tkSkill而不在sklllevel中查找它们。
更长的答案:最佳实践是:不要使用枚举。取决于“信念”,如果枚举可能稍微有用的话,就没有甚至只有少数情况。一种可能是,您不想使用引用表跳过联接以显示integer-id的textvalue/description。在您的设置中,您实际使用的是引用表,但仍希望使用枚举。
使用enum最接近最佳实践的方法是在tkSkill中将testskill定义为enum,而根本没有sklllevel-表(引用表)。
但是,我再次敦促你不要使用枚举。您可以将表定义为

CREATE TABLE `sklllevel` (
  `Id` tinyint(4) primary key,
  `Name` varchar(20) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后将该id用作tkSkill的外键。甚至
CREATE TABLE `sklllevel` (
  `Name` varchar(20) primary key
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后将tkSkill定义为varchar(20)并将其用作外键-虽然它将使用更多的空间,但如果这是您首先使用枚举的原因,则表中会有“可读”值。
在这里您可以找到一些枚举的背景:8 Reasons Why MySQL's ENUM Data Type Is Evil

10-07 16:04