简要模型概述:
我有一个student
和一个course
表。由于关系是多对多的,因此还有一个联结表student_course
(id_student
,id_course
),两列(复合)的约束为unique
。
我要解决的问题:
由于错误,unique
表的code
列上没有course
约束。它应该在code
列中唯一地标识course
。结果,course
表中有两行,code
列中的值相同。我要删除该重复项,检查是否没有其他重复项,并在unique
列上添加一个code
约束。不会失去与student
表的关系。
我解决问题的方法:
我已经创建了一个程序,可以执行我想要的操作。
CREATE OR REPLACE PROCEDURE REMOVE_COURSES
(
v_course_code IN VARCHAR2,
v_course_price IN VARCHAR2
)
AS
new_course_id NUMBER;
BEGIN
INSERT INTO course (CODE, PRICE) VALUES (v_course_code, v_course_price)
RETURNING ID INTO new_course_id;
FOR c_course_to_overwrite IN (SELECT *
FROM course
WHERE code = v_course_code AND id != new_course_id) LOOP
UPDATE student_course SET id_course = new_course_id WHERE id_course = c_course_to_overwrite.id;
DELETE FROM course WHERE id = c_course_to_overwrite.id;
END LOOP;
END REMOVE_COURSES;
/
我要解决的主要问题:
该过程不断给我一个关于unique
表上的student_course
约束违反的错误。但是我真的不确定如何使用new_course_id
,因此在联结表中没有两行具有相同的id_student
,id_course
的可能性。我需要解决什么?
其他:
我想仅出于学习目的使用程序解决该问题
已编辑
: CREATE TABLE student (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name VARCHAR2(150) NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE student MODIFY ID
GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH LIMIT VALUE);
CREATE TABLE course (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
code VARCHAR2(255) NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE course MODIFY ID
GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH LIMIT VALUE);
CREATE TABLE student_course (
id_student NUMBER NOT NULL,
id_course NUMBER NOT NULL,
PRIMARY KEY (id_student, id_course),
CONSTRAINT student_fk FOREIGN KEY (id_student) REFERENCES student (id),
CONSTRAINT course_fk FOREIGN KEY (id_course) REFERENCES course (id)
);
insert into student (name) values ('John');
INSERT INTO course (ID, CODE) VALUES (1, 'C_13');
INSERT INTO course (ID, CODE) VALUES (2, 'C_13');
commit;
INSERT INTO STUDENT_COURSE (ID_STUDENT, ID_COURSE) VALUES (1, 1);
INSERT INTO STUDENT_COURSE (ID_STUDENT, ID_COURSE) VALUES (1, 2);
commit;
CALL REMOVE_COURSES('C_13');
[23000][1] ORA-00001: unique constraint (SYS_C0014983) violated ORA-06512: near "REMOVE_COURSES", line 8
答案 0 :(得分:2)
您将使用相同的代码创建第三课程,而不是删除重复的代码之一,并尝试将所有旧课程中的所有学生转移到新课程中。该错误表明您已经有两个旧课程的学生。
您的游标循环查询是:
SELECT *
FROM course
WHERE code = v_course_code AND id != new_course_id
这将找到两个旧版本代码的所有联结记录,然后更新将这些联结记录的 all 设置为相同的新ID。
如果针对该代码的两个旧ID列出了任何学生(您的复合唯一键允许),那么他们都会被更新为相同的新ID。
所以说您正在查看的课程是[为您的示例代码更新的]:
ID CODE
-- ----
1 C_13
2 C_13
并且您有两个课程的学生结点记录,例如:
ID_STUDENT ID_COURSE
---------- ---------
1 1
1 2
您正在创建一门新课程:
ID CODE
-- ----
3 C_13
您的光标循环查找code = 'ABC' and ID != 3
,该循环将找到ID 1和2。因此,在循环的第一次迭代中,更新ID为1的行,这样您就可以了:
ID_STUDENT ID_COURSE
---------- ---------
1 3
1 2
然后在第二次迭代中,尝试更新ID为2的行,该行将尝试生成:
ID_STUDENT ID_COURSE
---------- ---------
1 3
1 3
这将打破唯一约束-因此产生错误。
您可能根本不想创建新课程,但是无论哪种方式,都需要从student_course
中删除重复的记录-也就是说,更新后的行将成为重复的记录。基本上,您需要查找具有两个现有课程ID条目的学生,然后删除其中一个。如果您不在乎该怎么做:
delete from student_course sc1
where id_course in (
select id
from course
where code = 'C_13'
)
and exists (
select null
from student_course sc2
join course c on c.id = sc.id_course
where sc2.id_student = sc1.id_student
and sc2.id_course > sc1.id_course
and c.code = 'C_13'
);
但是还有其他(可能更好)的方法。
然后,您可以选择将两个旧ID的所有剩余联结记录更新为新ID;或合并其中一个旧ID,然后删除另一个。
(您的问题表示您想自己解决总体任务,因此,我将避免尝试提供完整的解决方案-希望这可以帮助您理解和解决主要问题...)