我有一个包含很多行的表,但 name 和 id 列始终需要彼此相等。
示例:
name id value
'josh' 1 'blah'
'josh' 1 'foo'
'marc' 2 'bar'
'marc' 2 'boo'
任何时候都不应存在名称为“josh”的行,其中 id != 1,但组合可能会重复多次(因此它不是主键)。
该数据看起来没有标准化。
如果您仍然可以更改表格设计,我会创建一个单独的表格:
create table example_people (
id int not null primary key,
-- unique constraint fixes problem identified by philipxy
name varchar not null unique
)
然后将现有表重新定义为:
create table example_value (
id int not null,
value varchar,
constraint fk_value foreign key (id) references example_people (id)
);
检查整个表的触发器替代方案通常性能相当差,因为它必须序列化写访问。
这就是我要做的:
使用名称和 ID (PK) 创建表并检查名称是否唯一
创建一个包含值和第一个外键的表
问题的根源是功能依赖
id -> name
,它违反了3NF。
您可以通过将表分成两部分来解决这个问题:
CREATE TABLE name_table (
id int PRIMARY KEY,
name varchar(50) NOT NULL UNIQUE
);
CREATE TABLE value_table (
value varchar(50) PRIMARY KEY,
id int NOT NULL REFERENCES name_table
);
您可以通过 JOIN 轻松“重建”原始表,您可以将其包装到 VIEW 或存储过程(依赖于 DBMS)等中。
顺便说一句,尝试找出比这更好的名字!另外,请考虑向 value_table
添加
代理键是否值得。
您可以使用
找到不良数据SELECT id, FROM your_table
GROUP BY id HAVING count(first_name)>1;
还有一个类似的查询,其中 id 和 first_name 颠倒过来。我想你也可以联合起来。但正如 Laurence 和 Jose 所说,您应该做的是将 ID 和 Name 放入一个单独的表中,并仅使用其中一个作为外键。
首先,你不应该对不是主键的列使用id,这会误导其他队友理解这个数据库表中发生了什么。
看来您愿意使用 ( name, id ) 作为可能有多个值的键,
( 'josh', 1) --> 'blah', 'foo'
@Branko Dimitrijevic 的答案似乎对你有用,但是你不应该将 value 作为主键,因为你可能有另一个具有相同值的( name, id )组合,例如
( marc, 2 ) --> ( 'blah', 'foo', ... )
所以,这是我建议的 SQL 脚本
CREATE TABLE name_table (
id int PRIMARY KEY,
name varchar(50) NOT NULL UNIQUE
);
CREATE TABLE value_table (
value_table_id int PRIMARY KEY,
value varchar(50),
id int NOT NULL REFERENCES name_table
);