postgresql外键约束,以防止重复

时间:2012-03-19 12:06:45

标签: postgresql triggers foreign-keys duplicates

我正在使用触发器函数将数据写入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;

1 个答案:

答案 0 :(得分:5)

  

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

关于重复

不,您使用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”,“参数”}。

关于外键

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

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

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”}使用唯一约束才能使该特定外键约束起作用。