【问题标题】:postgresql foreign key constraints to prevent duplicatespostgresql 外键约束以防止重复
【发布时间】:2012-04-03 22:04:59
【问题描述】:

我正在使用触发器函数将数据写入 Postgresql 9.1 中的新表。现在一切正常,但我得到了重复。我可以使用外键约束来防止产生重复吗?我以前没有使用过外键约束。

这是表结构

DROP TABLE "obx" CASCADE;
   CREATE TABLE "obx" (
    "obxID" serial primary key,
    "Pid" varchar,
    "Sid" varchar,
    "SidOrig" varchar,
    "Parameter" varchar,
    "Result" varchar,
    "ResultOrig" varchar,
    "Units" varchar,
    "RefRange" varchar,
    "Flag" varchar,
    "FlagOrig" varchar,
    "OperatorID" varchar,
    "ObsTime" char(14),
    "MsgTime" char(14),
    "UnixTime" int4,
    "Analyzer" varchar,
    "Segment" varchar
    );

DROP TABLE "testcode" CASCADE;
CREATE TABLE "testcode" (
    "TcodeID" serial primary key,
    "Analyzer" varchar,
    "Parameter" varchar,
    "TestName" varchar,
    "ShortTestName" varchar,
    "TestID" int4
    ) ;
DROP TABLE "finaldata" CASCADE;
CREATE TABLE "finaldata" (
    "FdataID" serial primary key,
    "Pid" varchar,
    "Sid" varchar,
    "SidOrig" varchar,
    "Parameter" varchar,
    "Result" varchar,
    "ResultOrig" varchar,
    "Units" varchar,
    "OperatorID" varchar,
    "ObsTime" varchar,
    "MsgTime" varchar,
    "Analyzer" varchar,
    "TestName" varchar,
    "ShortTestName" varchar,
    "TestID" varchar,
    "XYchar1" varchar,
    "XYchar2" varchar,
    "XYchar3" varchar,
    "XYint1" int4,
    "XYint2" int4,
    "XYint3" int4,
    "XYGuid" uuid
    ) ;

以及触发功能:

BEGIN
      INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units"
        , "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
      SELECT ob."Pid", ob."Sid", ob."SidOrig", ob."Parameter", ob."Result", ob."ResultOrig", ob."Units"
        , ob."OperatorID", ob."ObsTime", ob."MsgTime", ob."Analyzer"
        , tc."TestName", tc."ShortTestName", tc."TestID"
      FROM obx ob
      JOIN testcode tc ON ob."Parameter" = tc."Parameter"
            WHERE ob."Sid" = NEW."Sid"
            AND ob."ObsTime" = NEW."ObsTime"
            AND ob."Parameter" = NEW."Parameter"
            AND ob."Analyzer" = NEW."Analyzer"
      AND tc."TestID" IS NOT NULL
           ;
      RETURN NEW;
  END;

【问题讨论】:

    标签: postgresql triggers foreign-keys duplicates


    【解决方案1】:

    我可以使用外键约束来防止产生重复吗?

    关于重复项

    不,您可以使用PRIMARY KEYNOT NULL UNIQUE 来防止重复。本声明

    CREATE TABLE "finaldata" (
        "FdataID" serial primary key,
    

    保证每一行都是唯一的,但不能保证该行所代表的东西——这是数据库设计者感兴趣的——是唯一的。让我举一个更小的例子。

    create table person (
      person_id serial primary key,
      full_name varchar(35) not null
    );
    
    insert into person (full_name) values ('Mendez, Cathy');
    insert into person (full_name) values ('Mendez, Cathy');
    insert into person (full_name) values ('Mendez, Cathy');
    insert into person (full_name) values ('Mendez, Cathy');
    insert into person (full_name) values ('Mendez, Cathy');
    
    select * from person;
    --
    1   Mendez, Cathy
    2   Mendez, Cathy
    3   Mendez, Cathy
    4   Mendez, Cathy
    5   Mendez, Cathy
    

    序列 ID 号使每个 都是唯一的,但它对行所代表的事物没有任何作用。如果我这样做了

    delete from person;
    alter table person
    add constraint person_uniq unique (full_name);
    

    那么这个插入就成功了,

    insert into person (full_name) values ('Mendez, Cathy');
    

    但是第二次运行它会因为这个错误而失败。

    ERROR: duplicate key value violates unique constraint "person_uniq"
    SQL state: 23505
    Detail: Key (full_name)=(Mendez, Cathy) already exists.
    

    因此,为了防止表 finaldata 中出现重复,您需要对某些列子集使用 UNIQUE 约束。

    我的猜测——这只是一个猜测——你至少需要 {"Pid", "Sid", "SidOrig", "Parameter"}。

    关于外键

    外键保证您放在一组列中的值已经存在于不同的表中

    例如,finaldata.pid 列中的值可能已经存在于另一个表中。如果 finaldata 列 {"Pid", "Sid", "SidOrig", "Parameter"} 中的值集应该已经存在于表 obx 中,那么像这样的外键约束将阻止无意义的数据找到它进入那些 finaldata 列。

    constraint finaldata_fk1
    foreign key ("Pid", "Sid", "SidOrig", "Parameter")
      references obx ("Pid", "Sid", "SidOrig", "Parameter") 
    

    您可能还需要on delete cascadeon update cascade 或其他一些参考操作。

    只有在引用的列上有唯一约束时,外键才会起作用。你还没有其中之一。您需要对 obx 列 {"Pid", "Sid", "SidOrig", "Parameter"} 设置唯一约束,才能使该特定外键约束起作用。

    【讨论】:

    • OP 之前已经问过这个问题两次了。潜在的问题是他的数据模型定义不正确:finaldata 表复制了 obx 的大部分数据(仅对主键的引用就足够了)甚至“参数”字段也不是候选键的一部分,因为它在功能上完全依赖于 PK(obx) -> 参数。一个独特的 FK(obx.ObxId 就足够了)我休息一下。
    • 我确实问了一个相关的问题,但那是关于触发器的。触发器部分现在正在工作。 finaldata 表是许多信息的副本,但另一个系统连接到数据库并通过 ODBC 从 finaldata 表中读取数据。这就是它按原样设置的原因。现在只有几个重复项,我相信唯一约束和外键会解决剩下的问题。谢谢
    • 唯一约束确实成功地阻止了重复项。不幸的是,它也阻止了通缉记录。机器分批发送记录 - 例如可能有 10 条记录。需要 6 个并且触发器正确过滤它们 - 除了产生一些重复项(通常为 1 或 2 个)。我现在将尝试在触发器上使用触发器,看看这是否有效。感谢您的清晰解释和@wildplasser 对触发器的早期帮助。
    • 再次重申:真正的问题不在于“触发器函数会生成一两个重复项”,而在于缺少数据模型。所有三个表似乎都具有作为 PK 的代理键,但 缺少可靠的真实 PK。缺少 1-3 个 FK 使混乱变得完整。即使 finaldata 应该是 obx 的 1->1 副本(假设参数存在于测试代码中),您也需要键约束。代理键没有任何意义。
    • @user1044111:您说,“唯一约束确实成功地阻止了重复项。不幸的是,它也阻止了想要的记录。”这意味着您错误地定义了唯一约束。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 2021-08-26
    • 2014-01-20
    • 2017-10-31
    • 2011-05-25
    • 1970-01-01
    相关资源
    最近更新 更多