如何确保两列始终等于同一事物

问题描述 投票:0回答:5

我有一个包含很多行的表,但 name 和 id 列始终需要彼此相等。

示例:

name      id      value
'josh'     1      'blah'
'josh'     1      'foo'
'marc'     2      'bar'
'marc'     2      'boo'

任何时候都不应存在名称为“josh”的行,其中 id != 1,但组合可能会重复多次(因此它不是主键)。

sql postgresql database-design database-normalization
5个回答
4
投票

该数据看起来没有标准化。

如果您仍然可以更改表格设计,我会创建一个单独的表格:

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)
);

检查整个表的触发器替代方案通常性能相当差,因为它必须序列化写访问。


3
投票

这就是我要做的:

  1. 使用名称和 ID (PK) 创建表并检查名称是否唯一

  2. 创建一个包含值和第一个外键的表


1
投票

问题的根源是功能依赖

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 添加

代理键
是否值得。


0
投票

您可以使用

找到不良数据
SELECT id, FROM your_table
GROUP BY id HAVING count(first_name)>1;

还有一个类似的查询,其中 id 和 first_name 颠倒过来。我想你也可以联合起来。但正如 Laurence 和 Jose 所说,您应该做的是将 ID 和 Name 放入一个单独的表中,并仅使用其中一个作为外键。


0
投票
  • 首先,你不应该对不是主键的列使用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
);
© www.soinside.com 2019 - 2024. All rights reserved.