【问题标题】:How to ensure two columns always equal the same thing如何确保两列总是相同的东西
【发布时间】:2014-11-19 13:21:57
【问题描述】:

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

例子:

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

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

【问题讨论】:

  • 如果是约束,则将其建模为约束。如果 {name,Id} 是唯一的,则使其唯一。 (name 似乎指的是更强大的域,也许id 甚至是多余的,或者反过来)
  • 我删除了标签 [唯一约束]。这个案例看起来有些相似,但完全不相关。
  • “总是需要相对于彼此相等的相同事物”没有任何意义。
  • 1) 当列 id 不是表的 id 时,你不应该调用它。 2) id 是人的身份证吗?那为什么没有 person 表保存这些人员,即 id 和 name?

标签: sql postgresql database-design normalization


【解决方案1】:

这就是我会做的:

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

  2. 创建一个表,其中包含第一个值和一个外键

【讨论】:

  • 这并不能阻止 Josh 出现两个不同的 id。
  • @philipxy 这是真的。 Branko Dimitrijevic 做对了。还是编辑了
【解决方案2】:

你的问题的根源是functional dependencyid -> 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 中添加surrogate key 是否值得。

【讨论】:

    【解决方案3】:

    这些数据看起来没有被标准化。

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

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

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

    【讨论】:

    • 这并不能阻止 Josh 出现两个不同的 ID。
    • 我想给你的建议与我给 OP 的建议相同:当列 id 不是表的 id 时,你永远不应该调用它。这很容易导致错误的假设,从而导致有缺陷的查询。
    • @ThorstenKettner 我永远不会在我设计的数据库中调用列 ID,但在回答问题时,我会使用提问者的约定。
    【解决方案4】:

    您可以通过

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

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

    【讨论】:

    • HAVING count(first_name)>1 没有帮助。 HAVING count(DISTINCT first_name)>1 会检测到一些 违规,但不会检测到其他违规,问题是如何先验防止 违规。
    • 啊,对,COUNT DISTINCT。但我认为这将捕获所有违规行为(如果您还对 count(id) 进行了反之查询。除了 NULL,还有什么可能会遗漏?至于防止先验,规范化......
    • 反之亦然,NULL,这就是所有的“其他”。是的,答案是标准化。
    猜你喜欢
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 2021-04-11
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多