有很多类似的问题,但我需要编写代码。
我知道,作为一种好习惯,我应该使用NAZWA
代替ID
,但我的作业是编写程序,而不是创建新序列。
如果MIEJSCOWOSC
没有重复,我需要插入新行,但必须增加ID_MIEJSCOWOSCI
。
表NAZWA
有两列( PK SELECT NVL(Max(m.ID_MIEJSCOWOSCI)+1,1) INTO mID
为NUMBER,CREATE OR REPLACE PROCEDURE WstawMiejscowosc (
NM IN Miejscowosc.Nazwa%TYPE)
AS
mID Miejscowosc.ID_MIEJSCOWOSCI%TYPE;
BEGIN
SELECT NVL(Max(m.ID_MIEJSCOWOSCI)+1,1) INTO mID
FROM Miejscowosc m;
INSERT INTO Miejscowosc m
select mID, NM
from Miejscowosc
where not exists (select 1 from Miejscowosc m where m.Nazwa = NM);
END;
/
为VARCHAR2)
我很清楚我的序列计数器
function createEvent() {
var calendarId = 'primary';
var start = getRelativeDate(1, 12);
var end = getRelativeDate(1, 13);
var event = {
summary: 'Lunch Meeting',
location: 'The Deli',
description: 'To discuss our plans for the presentation next week.',
start: {
dateTime: start.toISOString()
},
end: {
dateTime: end.toISOString()
},
attendees: [{
email: 'alice@example.com'
}, {
email: 'bob@example.com'
}],
attachments: [{
fileId: "1sGm4o0DVJFjJQun_oj1PWD9MuFCiikqamM7B0TkwH6w",
},
],
colorId: 9
};
event = Calendar.Events.insert(event, calendarId);
Logger.log('Event ID: ' + event.getId());
}
function getRelativeDate(daysOffset, hour) {
var date = new Date();
date.setDate(date.getDate() + daysOffset);
date.setHours(hour);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
}
我收到的时候工作不正常:
UPDATE或INSERT语句尝试插入重复键。
我该如何修复此代码?
'
答案 0 :(得分:3)
您的代码没有按照您的想法执行。
您的insert语句选择与输入参数NM
不匹配的所有行。因此,当表中有多个不匹配的行时,您的语句将尝试插入NM
的多行id
的相同派生值。这就是您获得ORA-00001
例外的原因。
解决方案:检查是否存在传递的值,如果找不到该值,则只插入一条记录。
CREATE OR REPLACE PROCEDURE WstawMiejscowosc (
NM IN Miejscowosc.Nazwa%TYPE)
AS
mID Miejscowosc.ID_MIEJSCOWOSCI%TYPE;
x varchar2(1);
cursor c_nm_exists (p_nm varchar2) is
select null into x
from Miejscowosc m
WHERE m.Nazwa = NM;
BEGIN
open c_nm_exists(p_nm);
fetch c_nm_exists into x;
if c_nm_exists%notfound then
select Max(m.ID_MIEJSCOWOSCI)+1,1)
into mID;
INSERT INTO Miejscowosc m
values (mID, NM);
end if;
close c_nm_exists;
END;
/
这是一段笨重的代码。但是,它比我之前的建议更好,因为它避免使用异常来实现业务逻辑,并且它处理匹配多行的传递NM值。它仍然在桌子上有多个选择,但各种限制使这不可避免。
我总是担心通过实施不良做法向学生展示如何做功课。为什么教师不能设置要求他们实施良好实践的学生练习?
具有推定索引的解决方案可能如下所示:
CREATE OR REPLACE PROCEDURE WstawMiejscowosc (
NM IN Miejscowosc.Nazwa%TYPE)
AS
mID Miejscowosc.ID_MIEJSCOWOSCI%TYPE;
x varchar2(1);
cursor c_nm_exists (p_nm varchar2) is
select null into x
from Miejscowosc m
WHERE m.Nazwa = NM;
BEGIN
open c_nm_exists(p_nm);
fetch c_nm_exists into x;
if c_nm_exists%notfound then
INSERT INTO Miejscowosc m
values (m_id_sequence.nextval, NM);
end if;
close c_nm_exists;
END;
/
虽然可以简化为MERGE:
CREATE OR REPLACE PROCEDURE WstawMiejscowosc (
NM IN Miejscowosc.Nazwa%TYPE)
AS
begin
merge into Miejscowosc m
using (select NM from dual ) q
on (q.NM = m.Nazwa)
when not matched then
insert values (m_id_sequence.nextval, NM);
end;
这是一个更好的解决方案,因为:
Max(m.ID_MIEJSCOWOSCI)+1,1)
检查表中是否存在值总是有问题的。如果两个会话同时检查相同的NM
,则不会找到它(因为Oracle的读取提交隔离级别):因此两者都将插入相同值的记录。防止这种情况的唯一安全方法是在相关列上放置UNIQUE约束。 (这也比在独占模式下锁定整个表格更好。)