несоответствие внешнего ключа в команде удаления для несвязанной записи

У меня есть следующие 5 таблиц, определенных с несколькими записями, вставленными в 1-й 4. Это использует sqlite 3.7.1.7 с включенной константой внешнего ключа.

create table if not exists subject (id varchar(50) primary key,desc varchar(100));
insert into subject (id,desc) values ("subject1","test subject");

create table if not exists subjectlevel (id_subject_id varchar(50) references subject(id) on delete cascade, id integer not null, desc varchar(100) not null, questmcmaxselections integer not null, primary key (id_subject_id,id));

insert into subjectlevel (id_subject_id,id,desc,questmcmaxselections) values ("subject1",1,"test subject1 level 1",4);

insert into subjectlevel (id_subject_id,id,desc,questmcmaxselections) values ("subject1",2,"test subject1 level 2",4);

create table if not exists questmc (id integer primary key, text varchar(300) not null, includeallanswers int not null, subject_id varchar(50), subjectlevel_id integer, foreign key (subject_id, subjectlevel_id) references subjectlevel (id_subject_id,id) on delete cascade); 

insert into questmc (text,includeallanswers,subject_id,subjectlevel_id) values ("this is a _ question", 1, "subject1",1);

create table if not exists questmcselection (id integer primary key, text varchar(100) not null, subject_id varchar(50), subjectlevel_id integer, foreign key (subject_id, subjectlevel_id) references subjectlevel (id_subject_id,id) on delete cascade);

insert into questmcselection (text,subject_id,subjectlevel_id) values ("this is a solution","subject1",1);

create table if not exists questmc_questmcselection(id integer primary key, answer integer not null, questmc_id integer, questmcselection_id integer, subject_id varchar(50), subjectlevel_id integer, foreign key (questmc_id) references questmc(id) on delete cascade, foreign key (questmcselection_id) references questmcselection (id) on delete cascade, foreign key (subject_id,subjectlevel_id) references questmc (subject_id,subjectlevel_id) on delete cascade, foreign key (subject_id,subjectlevel_id) references questmcselection (subject_id,subjectlevel_id));

если я попытаюсь удалить вторую запись в таблице subjectlevel, я получу ошибку несоответствия внешнего ключа, если определена таблица questmc_questmcselection.

sqlite> delete from subjectlevel where id=2;
Error: foreign key mismatch - "questmc_questmcselection" referencing "questmcselection"

questmc, questmcselection и questmc_questmcselection не имеют связанных существующих записей, которые должны предотвратить это удаление. Любая идея, почему эта ошибка возникает?


person rss181919    schedule 09.06.2013    source источник
comment
Похоже, ему не нравятся последние 2 внешних ключа, определенные в таблице questmc_questmcselection. Я удалил последний, а затем предпоследний (оба ключа (subject_id, subjectlevel_id)). Таким образом, возникает вопрос: поддерживает ли sqlite 3.7.1.7 несколько ссылок внешнего ключа на одну и ту же таблицу?   -  person rss181919    schedule 10.06.2013
comment
Может быть, мне следует задать более общий вопрос. У меня есть таблица вопросов с множественным выбором (mc) и таблица выбора, содержащая варианты, которые можно повторно использовать в вопросах. Мне нужна связь n:n между ними. Однако и в записях вопросов, и в записях выбора определены предмет и уровень предмета. Мне нужно убедиться, что связывание n:n позволяет связывать только идентичные типы. Как я могу сделать это на уровне БД?   -  person rss181919    schedule 10.06.2013


Ответы (2)


Эта ошибка не имеет ничего общего с этой конкретной записью subjectlevel.

Ваша проблема в том, что в ваших таблицах отсутствуют необходимые индексы. Ранее об этом не сообщалось, потому что этот оператор DELETE был первой командой, которая потребовала от SQLite проверки согласованности схемы базы данных.

person CL.    schedule 09.06.2013
comment
Я совершенно новичок в SQLite и несколько новичок в SQL. Какие индексы нужны, чтобы это работало? - person rss181919; 10.06.2013
comment
Я не знаю, возможно ли то, что я пытаюсь сделать, на уровне db. таблица A имеет идентификатор и поле типа. таблица B имеет идентификатор и поле типа. В обоих случаях id является первичным ключом, а type имеет значения, которые формируют один и тот же набор значений. таблица C обеспечивает связь n:n между A и B. Однако мне нужна ссылка только в том случае, если записи A и B имеют один и тот же тип. - person rss181919; 10.06.2013
comment
Получил это с помощью CL. Таблицы A и B должны включать идентификатор и тип ключа. Это уникальные индексы, на которые ссылался CL. Таблица C должна включать 3 поля (помощь, ставка, тип) и 2 ограничения fkey следующим образом. ссылка на внешний ключ (aid, type) A (id, type), ссылка на внешний ключ (bid, type) B (id, type) Это позволяет вам связать 2 записи из A и B в таблицу C, только если они имеют один и тот же тип ценность. Спасибо за помощь CL. - person rss181919; 10.06.2013

На основании ответа CL -

sqlite> create table parent(a);
sqlite> create table child(a, FOREIGN KEY (a) REFERENCES parent(a));
sqlite> pragma foreign_keys = ON;
sqlite> insert into parent values(3);
sqlite> insert into child values (3);
Error: foreign key mismatch - "child" referencing "parent"
sqlite> create unique index p_a on parent(a);
sqlite> insert into child values (3);
sqlite> _

Из документации:

Обычно родительский ключ ограничения внешнего ключа является первичным ключом родительской таблицы. Если [нет], то столбцы родительского ключа должны совместно подчиняться ограничению UNIQUE или иметь индекс UNIQUE, [который использует] последовательности сопоставления... в операторе CREATE TABLE для родительской таблицы.

то есть альтернатива:

sqlite> create table parent(a, b, UNIQUE (a, b));
sqlite> create table child (x, y, FOREIGN KEY (x, y) REFERENCES parent(a, b));

(это также выделяет внешние ключи с несколькими столбцами; они также работают с индексами...)

person Dragon    schedule 03.07.2014