`Неудачное ограничение не удалось` на составном первичном ключе, несмотря на использование триггера - PullRequest
0 голосов
/ 13 сентября 2018

Учтите, что мы получаем ошибку UNIQUE constraint failed при попытке вставить новую строку в таблицу.

Строка состоит из нескольких первичных ключей, которые связаны для создания ограничения составного ключа , а именно состоят из комбинации из 4 полей id, id_x, id_y и id_z.

Первая клавиша id должна быть клавишей unique, которая «автоматически увеличивается», тогда как id_x, id_y и id_z равны foreign keys.

Поскольку мы не можем использовать функцию с автоинкрементом для составного ключа в sqlite, мы прибегаем к использованию следующего триггера, где ищем наибольшее целое число для каждого поля и добавьте 1 для удовлетворения ограничения уникальность :

CREATE TRIGGER [autoincrement]
         AFTER INSERT
            ON table_main
          WHEN NEW.id IS NULL
BEGIN
    UPDATE table_main
        SET id = IFNULL((SELECT MAX(id) FROM table_main) + 1, 0),
        id_x = IFNULL((SELECT MAX(id_x) FROM table_main) + 1, 0),
        id_y = IFNULL((SELECT MAX(id_y) FROM table_main) + 1, 0),
        id_z = IFNULL((SELECT MAX(id_z) FROM table_main) + 1, 0);
END; 

Несмотря на это, мы все еще получаем UNIQUE constraint failed ошибку.

ОБНОВЛЕНИЕ: id_z имеет ограничение forign key.

Ответы [ 2 ]

0 голосов
/ 13 сентября 2018

Возможно, это не несмотря на триггер, а скорее из-за триггера.

Это обновляет все строк в table_main дотот же ключ (когда NEW.id равен нулю).Это, безусловно, приведет к нарушению ограничения, когда в table_main есть 2 (или более) строки.

UPDATE table_main
        SET id = IFNULL((SELECT MAX(id) FROM table_main) + 1, 0),
        id_x = IFNULL((SELECT MAX(id_x) FROM table_main) + 1, 0),
        id_y = IFNULL((SELECT MAX(id_y) FROM table_main) + 1, 0),
        id_z = IFNULL((SELECT MAX(id_z) FROM table_main) + 1, 0);

Если NEW.id не равно нулю, то проблема кроется в другом месте.

0 голосов
/ 13 сентября 2018

Поскольку мы не можем использовать функцию автоинкремента для составного ключа

Следующее имеет составной ключ с возрастающим уникальным идентификатором (то, что вы назвали автоинкрементом): -

DROP TABLE IF EXISTS table_main;
DROP TABLE IF EXISTS table_fkx;
DROP TABLE IF EXISTS table_fky;
DROP TABLE IF EXISTS table_fkz;
DROP TRIGGER IF EXISTS [autoincrement];
CREATE TABLE IF NOT EXISTS table_fkx (id INTEGER PRIMARY KEY, datacol TEXT);
CREATE TABLE IF NOT EXISTS table_fky (id INTEGER PRIMARY KEY, datacol TEXT);
CREATE TABLE IF NOT EXISTS table_fkz (id INTEGER PRIMARY KEY, datacol TEXT);
CREATE TABLE IF NOT EXISTS table_main (
    id INTEGER PRIMARY KEY, 
  id_x INTEGER REFERENCES table_fkx(id), 
    id_y INTEGER REFERENCES table_fky(id), 
    id_z INTEGER REFERENCES table_fkz(id), 
    UNIQUE(id, id_x, id_y, id_z)
);
/*
CREATE TRIGGER [autoincrement]
         AFTER INSERT
            ON table_main
          WHEN NEW.id IS NULL
BEGIN
    UPDATE table_main
        SET id = IFNULL((SELECT MAX(id) FROM table_main) + 1, 0),
        id_x = IFNULL((SELECT MAX(id_x) FROM table_main) + 1, 0),
        id_y = IFNULL((SELECT MAX(id_y) FROM table_main) + 1, 0),
        id_z = IFNULL((SELECT MAX(id_z) FROM table_main) + 1, 0);
END;
*/

INSERT INTO table_fkx VALUES (10,'some data'),(33,'more data'),(56,'even more data');
INSERT INTO table_fky VALUES (73,'some data'),(1200,'more data'),(560,'even more data');
INSERT INTO table_fkz VALUES (15,'some data'),(1500,'more data'),(123456,'even more data');
INSERT INTO table_main (id_x,id_y,id_z) VALUES 
    (10,1200,15),(56,1200,15),(33,560,15),(10,73,15) -- etc
;
-- INSERT what could be a considered a duplicate but now is not as the autoincremnt(sic) makes it unique
INSERT INTO table_main (id_x,id_y,id_z) VALUES (33,560,15); -- i.e. same as 3rd
SELECT * FROM table_main 
    JOIN table_fkx ON id_x = table_fkx.id 
    JOIN table_fky ON id_y = table_fky.id
    JOIN table_fkz ON id_z = table_fkz.id
;

Однако, если часть составного ключа не задана, это означает, что вы можете эффективно вставить потенциально бесполезные строки, которые ссылаются на одни и те же внешние ключи.

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