【问题标题】:Oracle SQL Developer: Integrity Constraint Violated (Parent Key Not Found) while inserting valuesOracle SQL Developer:插入值时违反完整性约束(未找到父键)
【发布时间】:2017-07-18 05:38:44
【问题描述】:

所以我被要求解决的原始问题是:

创建两个表: 员工:empID (PK)、empFname、empLname、deptID(FK) 和 部门:deptID(PK)、deptName、chairID。 chairID 是 Employee 表中的 empID。 在 Department 表中插入至少 3 行,在 Employee 表中插入至少 6 行。 在执行以下业务规则的 chairID 更新时创建触发器: 一名员工最多可以主持一个部门。 每个部门只有一个椅子。

我的解决方案是这样的:

create table Employee(empID NUMBER,
empFname VARCHAR2(20),
empLname VARCHAR2(20),
deptID NUMBER,
PRIMARY KEY (empID)
);

create table Department(deptID NUMBER,
deptName VARCHAR2(20),
chairID NUMBER,
PRIMARY KEY (deptID));

ALTER TABLE Employee
ADD FOREIGN KEY (deptID) REFERENCES Department(deptID);  

ALTER TABLE Department
ADD FOREIGN KEY (chairID) REFERENCES Employee(empID);   


INSERT INTO DEPARTMENT (deptID ,deptName,chairID ) VALUES (401,'COMPUTER SCIENCE',301);
INSERT INTO DEPARTMENT (deptID ,deptName,chairID ) VALUES (402,'ELECTRONICS',302);
INSERT INTO DEPARTMENT (deptID ,deptName,chairID ) VALUES (403,'MATHEMATICS',303);

INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1001,'Alen','Zer',301);
INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1002,'Beny','Ker',301);
INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1003,'Clen','Ler',302);
INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1004,'Dlen','Mer',302);
INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1005,'Elen','Ner',303);
INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID) VALUES (1006,'Flen','Oer',303);

CREATE OR REPLACE TRIGGER chairID_after_update
BEFORE UPDATE
ON Department
FOR EACH ROW

DECLARE
v_username varchar2(10);
v_count number;
v_sql varchar2(50);
BEGIN

select count(*) into v_count from Department where chairID = :new.chairID;
IF v_count = 0 then
v_sql := 'alter table set chairID ='+ :new.chairID;
execute immediate v_sql;
end if;

END;
/

我的表都创建并触发编译,但在尝试插入我的表时,我的所有插入语句都命中:

SQL 错误:ORA-02291:违反完整性约束 (SYSTEM.SYS_C0010675) - 未找到父键 02291. 00000 - “违反完整性约束 (%s.%s) - 未找到父键” *原因:外键值没有匹配的主键值。 *操作:删除外键或添加匹配的主键。

我应该怎么做才能解决这个问题?任何帮助/建议将不胜感激。

【问题讨论】:

  • 除了合理且有趣的逻辑困难外,您的陈述中还有其他错误。查看 INSERT 中员工的部门编号,它们是 301、302、303……但 DEPARTMENTS 表中的部门编号是 401、402、403……这应该如何工作?反过来看,你的员工是 1001, 1002, .... 所以 CHAIRID 不能是 301, 302, 303 - 它应该是 EMPLOYEES 表中实际员工的 ID!

标签: database oracle oracle-sqldeveloper


【解决方案1】:

显然你有一个逻辑问题(循环推理):你不能先创建部门,当没有员工的时候,因为对 CHAIRID 的外键约束会失效,你不能先创建员工,因为DEPTID 上的外键将失败。然而,您的数据模型显然是正确的。

那么,该怎么办?

一种解决方案是不要在一开始就添加外键。执行其他所有操作,插入数据,然后更改表以添加外键。

更好的解决方案是从一开始就添加 FK,但使它们可延迟并且最初延迟。然后插入数据,然后启用 FK 约束。 (实际上,使 FK 约束可延迟一个好主意,因为您将来可能会遇到类似的问题,并且您会喜欢这种灵活性。)

不过,最好的解决方案是像您一样创建具有所有约束的表。 (尽管让 FK 约束可以延迟)。然后插入部门,但所有 CHAIRID 都离开了NULL。然后插入 EMPLOYEE 行,最后更新 DEPARTMENTS 行以显示每个部门的正确 CHAIRID。

关键是,FK 列确实允许NULL - 利用它来打破恶性循环(循环逻辑)。

现在 - 您的要求是每个部门都应该有一个椅子...您可以使 CHAIRID 列不可为空。这又会妨碍我描述的计划。仅在 INSERT 和 UPDATE 语句之后添加该约束(当然还有触发器)。

【讨论】:

  • 非常感谢!我会立即尝试。
  • 老实说,我对 SQL 还很陌生,从来没有必要/学习过如何使 FK 可延迟。我可以通过将 ChairID 设为 null 来插入我的 3 个部门行,但在尝试将行插入员工时遇到了完整性约束。
  • @Lorden - 我明白了......你的陈述中还有其他错误。查看 INSERT 中员工的部门编号,它们是 301、302、303……但 DEPARTMENTS 表中的部门编号是 401、402、403……这应该如何工作?反过来看,你的员工是 1001, 1002, .... 所以 CHAIRID 不能是 301, 302, 303 - 它应该是 EMPLOYEES 表中实际员工的 ID!
  • 我犯了大错。会改变它,看看是否能解决我的问题。
  • 将部门 ID 更改为匹配,并将 empID 更改为唯一。一切编译正确。现在我只需要更新 Department 表的 NULL 值。
【解决方案2】:

一名员工只能主持一个部门。

每个部门只有一个椅子。

不需要触发器(除了用于教育目的)- 将DEPARTMENT.CHAIRID 列设为UNIQUENOT NULL

CREATE TABLE Employee(
  empID    NUMBER
           CONSTRAINT employee__empid__pk PRIMARY KEY,
  empFname VARCHAR2(20),
  empLname VARCHAR2(20),
  deptID   NUMBER       
);

CREATE TABLE Department(
  deptID   NUMBER
           CONSTRAINT department__deptid__pk PRIMARY KEY,
  deptName VARCHAR2(20),
  chairID  NUMBER
           CONSTRAINT department__chairid__nn NOT NULL
           CONSTRAINT department__chairid__u  UNIQUE
           CONSTRAINT department__chairid__fk REFERENCES employee ( empID )
);

ALTER TABLE Employee
ADD CONSTRAINT employee__deptid__fk
    FOREIGN KEY (deptID) REFERENCES Department(deptID);

插入具有NULL 部门ID 的员工,然后创建部门,最后更新员工以包含部门ID:

INSERT INTO EMPLOYEE (empID ,empFname ,empLname,deptID)
  SELECT 1001,'Alen','Zer', NULL FROM DUAL UNION ALL
  SELECT 1002,'Beny','Ker', NULL FROM DUAL UNION ALL
  SELECT 1003,'Clen','Ler', NULL FROM DUAL UNION ALL
  SELECT 1004,'Dlen','Mer', NULL FROM DUAL UNION ALL
  SELECT 1005,'Elen','Ner', NULL FROM DUAL UNION ALL
  SELECT 1006,'Flen','Per', NULL FROM DUAL;

INSERT INTO DEPARTMENT (deptID ,deptName,chairID )
  SELECT 301,'COMPUTER SCIENCE', 1001 FROM DUAL UNION ALL
  SELECT 302,'ELECTRONICS',      1004 FROM DUAL UNION ALL
  SELECT 303,'MATHEMATICS',      1005 FROM DUAL;

MERGE INTO EMLPOYEE dst
USING ( SELECT 301 AS deptid, 1001 AS empID FROM DUAL UNION ALL
        SELECT 301, 1002 FROM DUAL UNION ALL
        SELECT 302, 1003 FROM DUAL UNION ALL
        SELECT 302, 1004 FROM DUAL UNION ALL
        SELECT 303, 1005 FROM DUAL UNION ALL
        SELECT 303, 1006 FROM DUAL ) src
ON ( dst.empId = src.empid )
WHEN MATCHED THEN
  UPDATE SET deptId = src.deptID;

【讨论】:

  • 这很可能用于课堂,但在生产中您可能有 20,000 名员工。推迟 CHAIRID 上的 NOT NULL 约束更有效,在 CHAIRID 中创建具有 NULL 的部门,然后使用所有数据创建员工,然后只更新部门行(少得多),然后启用 NOT NULL 约束。
  • +1 指出处理额外约束的正确方法:在 CHAIRID 上放置 UNIQUE 和 NOT NULL 约束,而不是触发器。
猜你喜欢
  • 2016-05-31
  • 1970-01-01
  • 2020-07-19
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多