PostgreSQL - вставка / обновление нарушает ограничения внешнего ключа

12

Я новый в PostgreSQL. У меня есть 3 таблицы, одна таблица ссылается на первичные ключи другой 2 таблицы. Но я не мог вставить данные в Table3. Смотрите код ниже:

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

ОШИБКА: вставка или обновление таблицы «Table3» нарушает ограничение внешнего ключа «Table3_DataID_fkey» DETAIL: Ключ (DataID) = (27856) отсутствует в таблице «Table1».

Когда я попытался вставить данные в 3 таблицы, произошла ошибка. Я сослался на документацию по postgreSQL и изменил свой код следующим образом: (К сожалению, он показал другую ошибку)

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL REFERENCES Table1 ON DELETE RESTRICT,
  "Address" numeric(20) DEFAULT NULL REFERENCES Table2 ON DELETE CASCADE, 
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   PRIMARY KEY("DataID", "Address")
);

ОШИБКА: несколько первичных ключей для таблицы «Table3» не допускаются. ЛИНИЯ 65: PRIMARY KEY («DataID», «Address»)

Пожалуйста, помогите мне ... Как я могу создать ссылку?

Я изменил IDкак UNIQUEи удалил строку PRIMARY KEY ("ID"). В это время он показывает еще одну ошибку, как:

ОШИБКА: двойное значение ключа нарушает уникальное ограничение "Table3_pkey"

Haseena
источник

Ответы:

17

Есть несколько проблем с вашими столами. Я постараюсь сначала обратиться к внешним ключам, так как вы задали вопрос о них :)

Но перед этим мы должны понимать, что два набора таблиц (первые три, которые вы создали, и второй набор, который вы создали после удаления первого набора) одинаковы. Конечно, определение Table3вашей второй попытки имеет синтаксические и логические ошибки, но основная идея такова:

CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

Это определение говорит PostgreSQL примерно следующее: «Создайте таблицу с четырьмя столбцами, один из которых будет первичным ключом (PK), остальные могут быть NULL. Если вставлена ​​новая строка, проверьте DataIDи Address: если они содержат ненулевое значение ( скажем 27856), затем проверьте Table1for DataIDи Table2для Address. Если в этих таблицах такого значения нет, верните ошибку. " Последний пункт, который вы видели первым:

ERROR: insert or update on table "Table3" violates foreign key constraint 
    "Table3_DataID_fkey" DETAIL: Key (DataID)=(27856) is not present in table "Table1".

Так просто: если нет строки в Table1где DataID = 27856, то вы не можете вставить эту строку в Table3.

Если вам нужна эта строка, вы должны сначала вставить строку в Table1with DataID = 27856, и только потом пытаться вставить в Table3. Если вам кажется, что это не то, чего вы хотите, опишите в нескольких предложениях, чего вы хотите достичь, и мы поможем с хорошим дизайном.


А теперь о других проблемах.

Вы определяете свои PK как

CREATE all_your_tables (
    first_column NOT NULL DEFAULT '0',   
    [...]
    PRIMARY KEY ("ID"),  

Первичный ключ означает, что все элементы в нем отличаются друг от друга, то есть значения UNIQUE. Если вы дадите статический DEFAULT(например '0') UNIQUEстолбцу, вы будете постоянно испытывать неприятные сюрпризы. Это то, что вы получили в своем третьем сообщении об ошибке.

Кроме того, '0'означает текстовую строку, но не число ( bigintили numericв вашем случае). Используйте просто 0вместо этого (или вообще не используйте, как я писал выше).

И последний момент (я могу ошибаться здесь): в Table2, ваше Addressполе установлено на numeric(20). В то же время это ПК таблицы. Имя столбца и тип данных предполагают, что этот адрес может измениться в будущем. Если это правда, то это очень плохой выбор для ПК. Подумайте о следующей ситуации: у вас есть адрес «1234567890454», который имеет ребенок в Table3как

ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569

Теперь этот адрес меняется на что-то другое. Как сделать так, чтобы ваш дочерний ряд Table3следовал за своим родителем по новому адресу? (Есть решения для этого, но они могут вызвать много путаницы.) Если это ваш случай, добавьте столбец идентификатора в вашу таблицу, который не будет содержать никакой информации из реального мира, он просто будет служить значением идентификации (то есть , ID) для адреса.

Dezso
источник
Спасибо за ваше ценное предложение. Я постараюсь улучшить дизайн на основе ваших предложений. Теперь первая ошибка устранена.
Хасина
0

Все зависит от того, что вы хотите сделать с данными.

Первый пример - вы хотите, чтобы во всех таблицах были согласованные данные, но вы пытаетесь вставить значения, которые не соответствуют таблице1.

Второй пример - вы не хотите иметь непротиворечивые данные, но попробуйте заняться чем-то другим, не зная точно, что. Таблица не может иметь более одного первичного ключа.

Третий пример - вы все еще не знаете, чего хотите достичь, и накладываете на столбец UNIQUE ограничение, которое может иметь одно и то же значение несколько раз.

Если вы просто хотите вставить свои данные - избавьтесь от ссылок на внешние ключи в первом примере. Если вы хотите иметь согласованные данные во всех таблицах - выполните очистку данных, а затем вставьте в таблицы С ограничениями внешнего ключа.

tl; dr: вставить ваши данные в Table3 с кодом из первого примера - вставить пропущенные значения в столбец Table1.DataID, который существует в Table3.DataId.

BartekR
источник