Как предотвратить дублирование без первичного ключа в mysql - PullRequest
0 голосов
/ 08 мая 2020

У меня есть таблица с именем INVOICES, которая получает записи из сценария PHP. В нем много столбцов, но два наиболее важных - INVOICE_ID и INVOICE_TYPE. Обычно INVOICE_TYPE - это число от 0 до 3 , которое обозначает разные типы счетов-фактур.

До этого момента все работало гладко, пока два пользователя не отправили счета-фактуры, в то время как на сервере произошел сбой, и он записал оба как один и тот же INVOICE_ID. Причина в том, что сценарий PHP считывает MAX INVOICE_ID из INVOICE_TYPE, затем добавляет 1 , а затем вставляет новую строку с этим INVOICE_ID. По сути, это программно primary key. 99,9% раз это работало, но в тот раз это была проблема.

Я пытался найти SQL решения, но не знаю об этом в достаточной степени. Я попытался сделать это сам в запросе SQL для чтения MAX, приращения и вставки, но просто выдает исключение, которое вы не можете выбрать и вставить из той же таблицы одновременно.

Что я интересно, есть ли автоматическое приращение, которое могло бы быть условным для INVOICE_TYPE, чтобы увеличивать только при совпадении типа. На этом этапе могут помочь любые предложения.

Ответы [ 4 ]

2 голосов
/ 08 мая 2020

Уникальный индекс по двум столбцам (INVOICE_ID, INVOICE_TYPE) приведет к сбою одного из таких запросов с ошибкой.

CREATE UNIQUE INDEX id_type_unique ON INVOICES (INVOICE_ID, INVOICE_TYPE);
INSERT INTO INVOICES (INVOICE_ID, INVOICE_TYPE) VALUES (1, 5);  -- okay
INSERT INTO INVOICES (INVOICE_ID, INVOICE_TYPE) VALUES (1, 5);  -- error
0 голосов
/ 08 мая 2020

Если вы вставляете только одну строку в одну таблицу одновременно, самое простое решение - применить уникальный индекс к обоим столбцам.

CREATE UNIQUE INDEX invoice_id_type_unique
ON INVOICES(INVOICE_ID,INVOICE_TYPE);

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

START TRANSACTION;
SELECT @invoice_id:=MAX(INVOICE_ID) FROM INVOICES WHERE INVOICE_TYPE=1;
INSERT INTO INVOICES (...,@invoice_id,...);
...
... #OTHER QUERIES UPDATING DATA
COMMIT;
0 голосов
/ 08 мая 2020

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

НАЧАТЬ СДЕЛКУ;

ВЫБЕРИТЕ значение В результат FROM Последовательности, ГДЕ имя, например paramSeqName FOR UPDATE;

UPDATE Sequences SET value = value + 1 WHERE name like paramSeqName;

COMMIT;

Есть хороший пример здесь: http://www.microshell.com/database/mysql/emulating-nextval-function-to-get-sequence-in-mysql/

0 голосов
/ 08 мая 2020

make (INVOICE_ID) as UNIQUE, это решит вашу проблему, sql не позволит дублировать значение в том же столбце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...