ограничения внешнего ключа postgresql для предотвращения дублирования - PullRequest
0 голосов
/ 19 марта 2012

Я использую функцию триггера для записи данных в новую таблицу в 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 Ответ

5 голосов
/ 19 марта 2012

Можно ли использовать ограничения внешнего ключа для предотвращения создания дубликатов?

О дубликатах

Нет, вы используете либо PRIMARY KEYили NOT 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

Серийный идентификационный номер делает каждую строку уникальной, но она ничего не делает для того, что представляет строка.Если я сделал это

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, вам нужно УНИКАЛЬНОЕ ограничение для некоторого подмножества столбцов.

Моя догадка - и это всего лишь предположение - состоит в том, что вам нужно по крайней мере {"Pid", "Sid"," SidOrig "," Параметр "}.

О внешних ключах

Внешние ключи гарантируют, что значения, введенные в один набор столбцов, уже существуют в другой таблице .

Например, значения в столбце 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 cascade, on update cascade или какое-либо другое ссылочное действие.

Внешний ключ будет работать только при наличии уникального ограничения на указанные столбцы.У вас еще нет одного из них.Вам понадобится уникальное ограничение на столбцы obx {"Pid", "Sid", "SidOrig", "Parameter"}, чтобы это конкретное ограничение внешнего ключа работало.

...