我有一个创建为
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 with
testSkill.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来连接它们。
要将它用作外键,您确实需要同时拥有tkSkill
和level
才能成为同一个枚举-但是您需要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