Почему я продолжаю нарушать уникальное ограничение?

avatar
Sean
8 апреля 2018 в 11:41
7996
4
0
create table Doctor
(
    docID INTEGER,
    appointID INTEGER not null,
    regnum CHAR(6),   
    doc_name VARCHAR(40),
    doc_gender CHAR(1),
    qual VARCHAR(80),       

    primary key (docID),
    foreign key (appointID) references Appointment
);

INSERT INTO Doctor 
VALUES(1, 1, 'ABC001', 'Steven Arrow', 'M', 'Bachelor of Medicine  and Surgery, Deakin University, 1980');

Я постоянно получаю сообщение об ошибке:

ORA-00001: уникальное ограничение (S3705969.SYS_C001160460) нарушено

Что я делаю не так?

Источник
Gordon Linoff
8 апреля 2018 в 11:44
2

Предположительно, потому что у вас уже есть строка, в которой docID равно "1".

krokodilko
8 апреля 2018 в 11:48
0

Скорее всего в этой таблице уже есть запись с DocID=1. Запустите SELECT * FROM Doctor where DocId=1, чтобы проверить, существует ли такая запись. Существует ограничение primary key (docID),, которое предотвращает дублирование в столбце ID.

Ответы (4)

avatar
APC
8 апреля 2018 в 13:43
0

Сообщение ORA-00001 означает, что вы вставляете повторяющееся значение в столбец. Глядя на ваше выражение create table, мы можем предположить, что это будет DOC_ID, поэтому вы, должно быть, уже вставили строку с DOC_ID = 1.

Почему же сообщение об ошибке такое загадочное?

ORA-00001: уникальное ограничение (S3705969.SYS_C001160460) нарушено

Загадочное имя связано с тем, что вы создали первичный ключ, не называя ограничение, поэтому Oracle сгенерировал его для вас; ограничения не являются первоклассными объектами базы данных (в отличие от таблиц), но им по-прежнему требуются имена.

Что вы можете сделать, так это назвать ограничение, где вы его создаете, например,

create table Doctor
(
   docID INTEGER,
   appointID   INTEGER ,
   regnum  CHAR(6),   
   doc_name    VARCHAR(40),
   doc_gender  CHAR(1),
   qual    VARCHAR(80),        
   constraint DOCTOR_PK primary key (docID),
   constraint DOCTOR_APPOINTMENT_FK foreign key (appointID) 
        references Appointment(column_name) 
);

Но если вы обнаружите, что работаете со схемой, в которой отсутствуют имена, вы можете использовать словарь данных, чтобы узнать, что происходитL

select c.table_name
      , decode (c.constraint_type
                , 'P', 'Primary key'
                , 'U', 'Unique key'
                , 'R', 'Foreign key'
                , 'C', 'Check') as constraint_type
      , cc.column_name
from all_constraints c
      join all_cons_columns cc
      on cc.owner = c.owner
      and cc.table_name = c.table_name
      and cc.constraint_name = c.constraint_name
where c.owner = 'S3705969' 
and c.constraint_name = 'SYS_C001160460'
order by cc.position
/

Кстати, кажется, что ваш внешний ключ неправильный. У одного врача много назначений, поэтому в таблице APPOINTMENT должен быть столбец DOCTOR_ID с внешним ключом, ссылающимся на таблицу DOCTOR.

avatar
Lukasz Szozda
8 апреля 2018 в 12:03
2

Вы должны разрешить Oracle заполнять столбец docId, используя IDENTITY:

create table Doctor
(
docID INTEGER GENERATED ALWAYS AS IDENTITY not null ,
appointID   INTEGER ,
regnum  CHAR(6),   
doc_name    VARCHAR(40),
doc_gender  CHAR(1),
qual    VARCHAR(80),        
primary key (docID),
foreign key (appointID) references Appointment(column_name)  
);

INSERT INTO Doctor(col_names, ...)    --skip docID
VALUES( 1, 'ABC001', 'Steven Arrow', 'M',
      'Bachelor of Medicine  and Surgery, Deakin University, 1980');
avatar
Gordon Linoff
8 апреля 2018 в 11:55
1

Это действительно ошибка, возникающая при повторении значения первичного ключа. Лучший способ исправить это — использовать Oracle 12C+ и использовать сгенерированный столбец идентификации для первичного ключа.

Относительно простой подход состоит в том, чтобы использовать последовательность и убедиться, что она используется для всех вставок:

CREATE SEQUENCE doctor_sequence;

INSERT INTO Doctor( . . . )
    VALUES(doctor_sequence.enxtval, 1, 'ABC001', 'Steven Arrow', 'M', 'Bachelor of Medicine  and Surgery, Deakin University, 1980');

. . . потому, что вы должны явно перечислить все столбцы при выполнении вставки.

Я должен отметить, что при использовании последовательностей самым безопасным подходом является использование триггеров вставки, поэтому использование последовательности не зависит от логики приложения. Однако триггер может не понадобиться для того, что вы делаете. А если вы используете более поздние версии Oracle, вы можете просто использовать сгенерированный столбец.

avatar
Xenon
8 апреля 2018 в 11:48
0

БД, вероятно, создала уникальное ограничение для какого-то столбца после того, как вы создали таблицу, или уже есть строка с идентификатором 1. Вы пытались запросить таблицу для всех данных? Если перед вставкой он пуст, то ограничение уникальности не должно нарушаться. Попробуйте DESCRIBE DOCTOR, чтобы увидеть, есть ли уникальные ограничения.