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”详细信息:表(Table1)中不存在键(DataID)=(27856)。

当我尝试将数据插入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”的多个主键不允许LINE 65:PRIMARY KEY(“ DataID”,“ Address”)

请帮助我...如何创建参考?

我更改了IDas UNIQUE并删除了这一行PRIMARY KEY ("ID")。当时它显示了另一个错误,例如:

错误:重复的键值违反了唯一约束“ Table3_pkey”

Answers:


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。如果插入了新行,请检查DataIDAddress:如果它们包含非NULL值(说27856),然后检查Table1DataID,并Table2Address。如果这些表中没有这样的值,然后返回一个错误。” 您首先看到的最后一点:

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

如果你需要该行,你应该首先将行插入Table1DataID = 27856,然后才尝试插入Table3如果您觉得这不是您想要的,请用几句话描述您想要达到的目标,我们会为您提供一个好的设计。


现在介绍其他问题。

您将PK定义为

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

主键意味着其中的所有项目都互不相同,即值是UNIQUE。如果为列提供静态值DEFAULT(如'0'UNIQUE,则始终会遇到很多意外情况。这是您在第三条错误消息中所得到的。

此外,'0'是指文本字符串,而不是数字(bigintnumeric您的情况)。0而是简单地使用它(或者完全不使用它,正如我在上面所写的那样)。

最后一点(在这里我可能是错的):在Table2,您的Address字段设置为numeric(20)。同时,它是表的PK。列名和数据类型表明此地址将来可以更改。如果这是真的,那么对于PK来说是一个非常糟糕的选择。想想以下情形:您有一个地址“1234567890454”,其中有一个孩子Table3喜欢

ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569

现在,该地址正巧更改为其他地址。您如何让您的子行Table3跟随其父行到新地址?(有解决方案,但可能会造成很多混乱。)如果是这种情况,请向表中添加一个ID列,该列将不包含来自现实世界的任何信息,它仅用作标识值(即,ID)作为地址。


感谢您的宝贵建议。我会根据您的建议尝试更好的设计。现在,第一个错误已解决。
Haseena 2012年

0

这完全取决于您要如何处理数据。

第一个示例-您希望所有表中的数据都一致,但是您尝试插入与Table1不匹配的值。

第二个例子-您不想拥有一致的数据,但是尝试做其他事情,而又不完全知道是什么。表不能有多个主键。

第三个示例-您仍然不知道要实现什么并将UNIQUE约束放在可能多次具有相同值的列上。

如果只想插入数据,请在第一个示例中摆脱外键引用。如果要在所有表中具有一致的数据-进行数据清理,然后将其插入具有外键约束的表中。

tl; dr:使用第一个示例中的代码将数据插入到Table3中-将缺少的值插入到Table3.DataId中存在的Table1.DataID列中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.