Как избежать дублирования значений первичного ключа с помощью INSERT INTO SELECT и NOT EXISTS - PullRequest
1 голос
/ 07 марта 2019

Я пытаюсь вставить строки в пустую таблицу, в которой хранится информация о клиенте из другой таблицы.Первичный ключ - ID, и я использую следующий запрос для выбора записей:

INSERT INTO client (id, name, surname, surname2, dob, phone, email, address) 
SELECT DISTINCT NVL(cl_dni, floor(dbms_random.value(10000000,100000000))), 
cl_name, cl_surn1, cl_surn2, cl_birth, cl_phone, cl_email, cl_address
FROM purchases WHERE NOT EXISTS(SELECT id from client WHERE client.id = purchases.cl_dni);

Моя главная цель - создать случайное целое число для идентификатора, если оно равно нулю, и убедиться, что я не добавляю дубликат идентификатора.значения в таблицу, однако это дает мне уникальную ошибку нарушения ограничения.Означает ли это, что есть проблема с предложением WHERE NOT EXISTS?Как можно использовать INSERT INTO SELECT, чтобы избежать дублирования значений первичного ключа?

Ответы [ 3 ]

0 голосов
/ 07 марта 2019

Что ж, random не гарантирует уникальность, и часть NOT Exists ничего не найдет, потому что таблица назначения пуста.

В чистом SQL это не так просто, но, поскольку вы используете БД Oracle, вы можете легкосделай это в plsql.Это должно работать в принципе :).Не проверено.

declare
    iOffset pls_interger;
begin
--  Use max value as offset
    select max(cl_dni) into iOffset from purchases;
--  Use 1 if no id exists at all
    iOffset := nvl(iOffset,1);  
--  Loop thru all purchases
    for rec in (SELECT distinct cl_dni,cl_name, cl_surn1, cl_surn2, cl_birth, cl_phone, cl_email, cl_address FROM purchases) loop
        INSERT INTO client (id, name, surname, surname2, dob, phone, email, address) 
               VALUES (NVL(rec.id, iOffset), rec.cl_name .....   );
        iOffset := iOffset + 1;    
    end loop;
end;

РЕДАКТИРОВАТЬ Еще один подход заключается в том, чтобы найти максимальное значение, которое я покупаю, и добавить значение rownum, чтобы получить уникальный идентификатор.Попробуйте это, не проверено ...

INSERT INTO client (id, name, surname, surname2, dob, phone, email, address) 
SELECT DISTINCT NVL(cl_dni, mv.val + rownum), cl_name, cl_surn1, cl_surn2, cl_birth, cl_phone, cl_email, cl_address 
FROM purchases, 
    (select max(cl_dni) val from purchases) mv; 
0 голосов
/ 07 марта 2019

Возможно, лучший способ - создать последовательность, начиная с 10000000:

 CREATE SEQUENCE SEQ_ID
     START WITH     10000000
     MAXVALUE 99999999
     INCREMENT BY   1
     NOCACHE
     NOCYCLE;

и сделать что-то вроде этого:

INSERT INTO client (id, name, surname, surname2, dob, phone, email, address) 
SELECT NVL(cl_dni, SEQ_ID.nextval), 
cl_name, cl_surn1, cl_surn2, cl_birth, cl_phone, cl_email, cl_address
FROM purchases WHERE NOT EXISTS(SELECT id from client WHERE client.id = purchases.cl_dni);

Проблема этого подхода заключается в том, что вы могли бысоздать с последовательностью существующий cl_dni

0 голосов
/ 07 марта 2019

Какое уникальное ограничение на клиентской таблице? Могу ли я предположить, что в таблице покупок есть дуплики, так как вы используете разные данные при получении данных? Может существовать вероятность того, что в закупках будет несколько записей: одна с действительным идентификатором клиента, а другая с нулевым идентификатором клиента, но другие значения атрибута совпадают. Таким образом, вы пытаетесь вставить 2 записи в клиентскую таблицу из покупок, одну с действительным идентификатором и одну со случайным значением, но с теми же атрибутами для уникального ограничения, определенного для клиентской таблицы.

...