powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Проблемы с созданием foreign key и предварительной очисткой данных
21 сообщений из 21, страница 1 из 1
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040153
micis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Стандартная ситуация: есть справочная таблица (T1) и много таблиц документов (T2). Надо теперь добавить вторичный ключ в документы.
Но перед этим надо заNULLить поле, которое участвует в создании ключа и ссылается на несуществующие данные:
Код: sql
1.
2.
update t2 set t1_id=null where t1_id not in (select id from t1);
alter table t2 add constraint FK_t2_1 foreign key (t1_ID) references t1(ID);


Так всё работает отлично. Но т.к. таблиц-документов много, то я пробую сделать это же в блоке:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
execute block
as
declare tbl varchar(50);
begin
  for select 't2' from rdb$database into :tbl do begin
    execute statement 'update '||tbl||' set t1_id=null where t1_id not in (select id from t1)';
    execute statement 'alter table '||tbl||' add constraint FK_'||tbl||'_1 foreign key (t1_ID) references t1(ID)';
  end
end;


В селекте одна таблица (для простоты примера).
В итоге получаю ошибку при создании вторичного ключа: "Foreign key reference target does not exist".
Если закомментировать создание ключа, прогнать блок, а затем раскомментировать и запустить блок ещё раз, то ключ создаётся!
Пробовал уже первый execute выполнять в "autonomous transaction", но результат тот же.
Подскажите, как исправить?
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040201
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Выполняй оба ES в автономных тр-циях.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040230
micis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hvladВыполняй оба ES в автономных тр-циях.Попробовал, ошибка та же: violation of FOREIGN KEY constraint "". violation of FOREIGN KEY constraint "FK_T2_1" on table "T2". Foreign key reference target does not exist.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040239
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
micis,

покажи как пробовал.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040241
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
micis,

да, я поспешил с советом.
В одном блоке не получится, т.к. внешняя тр-ция всё ещё видит "неправильные" запписи и FK не может быть построен.

Можно в блоке просто сгенерить команды и потом их уже выполнить.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040244
micis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Симонов Денис,

Вот создание тестовых таблиц:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
create table t1 (id integer not null, f2 varchar(10));

create table t2 (id integer not null, t1_id integer,  f3 varchar(10));

alter table t1 add constraint pk_t1_id primary key(id);
alter table t2 add constraint pk_t2_id primary key(id);

insert into t1 values(1,'111');
insert into t1 values(2,'222');

insert into t2 values(1,1,'111');
insert into t2 values(2,1,'111');
insert into t2 values(3,2,'222');
insert into t2 values(4,5,'555');

Вот сам блок:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
execute block
as
declare tbl varchar(50);
begin
  for select 't2' from rdb$database into :tbl do begin
    in autonomous transaction do
      execute statement 'update '||tbl||' set t1_id=null where t1_id not in (select id from t1)';
    in autonomous transaction do
      execute statement 'alter table '||tbl||' add constraint FK_'||tbl||'_1 foreign key (t1_ID) references t1(ID)';
  end
end;


Причём update выполняется, запрос
Код: sql
1.
select * from t2 where t1_id not in (select id from t1);

ничего не возвращает.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040251
micis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hvlad,

Да, я уже склоняюсь к тому, что бы сделать 2 блока (точнее, так точно будет работать, я проверял).
Просто мне хотелось использовать один блок, потому что в нём я в начале сохраняю состояние проверок (процедура возвращает 0 или 1), выключаю проверки, делаю эти самые изменения и в конце проверки активирую как было. Может подскажете как можно это всё реализовать по-другому?
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040328
afgm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот интересно, а выполнятор скриптов в ядре сервера облегчил бы ситуацию?
из серии
Код: sql
1.
2.
if exists (...table_name...) then
   DDL


Раз уж разработчики категорически против управления транзакциями в процедурах...
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040336
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
afgm,

IBEScript такое умеет

http://www.ibexpert.net/IBE/INDEX.PHP?n=Doc.ScriptExecutive $IFEXISTS

This tests the existence of the specified database object or data and executes the following block of the script if the object or data do exist in the database.

Syntax

1. {$IFEXISTS DOMAIN|TABLE|VIEW|TRIGGER|PROCEDURE|

EXCEPTION|GENERATOR|UDF|ROLE object_name}
2. {$IFEXISTS select_statement}
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040338
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
afgm,

и ещё никакого "выполнятора скриптов" в ядре сервера не существует
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040360
afgm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Дениси ещё никакого "выполнятора скриптов" в ядре сервера не существует
Читаем внимательно "облегчил бы?"
Я знаю что его нет. В том то всё и дело, что его нет (вдруг оно много кому надо, просто молчат :) ). Есть стейтменты и парсер в ISQL, например.
Но как и ISQL, IBEScript - внешний парсер. Из-за чего разработчикам приходится таскать с собой этот огород, либо писать свой велосипед. Вот мне лично обидно за FB. В MSSQL, например, я могу написать скрипт, который выполнить практический все манипуляции по апгреду базы. Никаких внешних тулзятин для этого не надо. А для FB приходится изобретать.
К слову о IBEScript. Не умоляя достоинств автора, в нём в своё время наловили багов. Причём не факт что все легко устранимы, потому как пользовали импорт-экспорт FB <-> Excel. В результате не пошёл как промышленный скриптер. Вот экстрактить базу в систему контроля версий, да ещё и с предварительным настройкам, да ещё некоторый таблички с данными - это да, ничего лучше не знаю.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040362
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
micisПросто мне хотелось использовать один блок, потому что в нём я в начале сохраняю состояние проверок (процедура возвращает 0 или 1), выключаю проверки, делаю эти самые изменения и в конце проверки активирую как было. Может подскажете как можно это всё реализовать по-другому?Первый раз в этой теме вижу слово "проверки". Что это такое - не знаю и сам придумывать не буду.
Так что пока что ничего подсказать просто не могу.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040377
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
afgm,

это обход проблемы с боку, а не её решение. Я то же против выполнения DDL в процедурах и управления транзакциями в них. Хотя бы потому, что это не возможно в компилируемых процедурах даже чисто теоретически.

Код: sql
1.
2.
3.
4.
5.
6.
create procedure p
as
begin
  create table t(i int);
  insert into t(i) values (1); -- при проверки зависимостей обломится ещё на этапе компиляции
end



Но я ничего не имею против выполнения DDL и DML операторов в одной транзакции. Хоть это сделать не так просто как "выполнятор скриптов", зато правильней.

И не надо сравнивать с MS SQL. У них процедура это как раз больше похоже на набор операторов ибо она интерпретируется. С одной стороны плюс ибо скрипты проще накатывать, с другой - минус никакого контроля зависимостей. Всё легко можно поломать.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040438
afgm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис
Код: sql
1.
2.
3.
4.
5.
6.
create procedure p
as
begin
  create table t(i int);
  insert into t(i) values (1); -- при проверки зависимостей обломится ещё на этапе компиляции
end



Да тут и времянки ещё можно добавить (не GTT, а времянки-времянки) и много чего ещё.
Симонов ДенисНо я ничего не имею против выполнения DDL и DML операторов в одной транзакции. Хоть это сделать не так просто как "выполнятор скриптов", зато правильней.

Ну вот человек хотел написать процедуру автоматизации и напоролся. Без внешнего выполнятора как-то не получается.
Симонов ДенисИ не надо сравнивать с MS SQL. У них процедура это как раз больше похоже на набор операторов ибо она интерпретируется. С одной стороны плюс ибо скрипты проще накатывать, с другой - минус никакого контроля зависимостей. Всё легко можно поломать.
Оффтоп, но раз уж начали.
Ну тут есть и плюсы и минусы. Рефакторить базу на FB иной раз ох как "весело". А ловить запоздалые поломки на MSSQL просто "чудо".
Вон PG тексты вьюх переписывает при переименовании таблицы :)
Я вот не могу сказать в пользу жёского контроля зависимостей. Он кончено помогает не напортачить. Вот прям сразу. Но вот переименовать что-либо... Может ближе к идеалу в Оракле? Я не совсем в теме этой СУБД, но галка валид/невалид пытается угодить обоим подходам?
Вообще, как правило, недовольство людей при переходе с одной СУБД на другую вызвано тем, что недовольство зреет вокруг "неудобств", являющихся прямым следствием архитектурных особенностей. Вот знаю я приколы FB. Ну не так просто сделать индексные сканы. Скрипты тоже непонятно как вставить, если вообще возможно и нужно. Длина идентификаторов - легаси и это поломать низя, и т.д.
Особенно удивительно и приятно, когда разработчикам таки удаётся сделать то, что казалось почти невозможным. В MSSQL появилась версионность, и работает на удивление не плохо. У FB тоже таких свершений было достаточно.
Вот перечитывал письмо Джима с заголовком про распределённый firebird, так я лично не представляю количество усилий для реализации написанного, и есть ли оно в отдалённых планах...
Это я к чему. Верю в развитие. Верю в лучшее. А тулза для выполнения скриптов должна быть кроссплатформенной, оттестированной (может даже стандартизированной), и желательно, открытой.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040511
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Выполнение DDL не подчиняется правилам видимости данных, которые установлены для DML-транзакций (открытие этой тайны - тут ).

Например, для уровня READ COMMITTED транзакция "А" должна видеть изменения, зафиксированные транзакцией "Б", если эта "А" перечитывает данные, которые меняла "Б".

Допустим, тр-ция "А" стартовала в 10:00 и в этот момент в деталь-таблице еще были записи, не позволяющие установить FK.
Далее, в 10:01 стартовала тр-ция "Б" и выполнила:
update t_detail d set pid = null where not exists(select * from t_master m where m.id = d.pid);
commit;

Если затем, в 10:02, тр-ция "А" выполнит alter table t_detail add constraint t_detail_fk foreign key(pid) references t_master(id); - то она получит облом. Несмотря на то, что этот "alter table" будет идти в TIL = READ COMMITTED и данные в таблице уже корректны.

Вот пример:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
 session #1 

Database: /3255:e25, User: SYSDBA
SQL> recreate table td4(id int primary key, pid int);
SQL> commit;
SQL>
SQL> recreate table tm(id int constraint tm_pk primary key);
SQL> commit;
SQL>
SQL> insert into tm values(1);
SQL> commit;
SQL>
SQL> insert into td4 values(1, 1);
SQL> insert into td4 values(2, 2);
SQL> commit;

 session #2  // запускаем этот ISQL после того, как выполнили начальные команды в session #1

Database: /3255:e25, User: SYSDBA
SQL> commit; set transaction read committed;
SQL> select d.*, m.* from td4 d left join tm m on d.pid = m.id;

          ID          PID           ID
============ ============ ============
           1            1            1
           2             2        <null> -- т.е. видим запись дочерней таблицы, в которой PID  не  позволит установить FK


 session #1 

SQL> update td4 d set pid = null where not exists(select * from tm m where m.id = d.pid);
SQL> commit;

 session #2  // делаем  в той же  транзакции, что была запущена перед этим

SQL> select d.*, m.* from td4 d left join tm m on d.pid = m.id;

          ID          PID           ID
============ ============ ============
           1            1            1
           2        <null>        <null> -- видим, что теперь в дочерней таблице PID = null, след-но, установить FK - можно ?...


SQL> alter table td4 add constraint td4_fk foreign key(pid) references tm(id);
Statement failed, SQLSTATE = 23000
violation of FOREIGN KEY constraint "TD4_FK" on table "TD4"
-Foreign key reference target does not exist
-Problematic key value is ("PID" = NULL)

 SQL> commit; 

-- И только теперь можно будет установить FK, хотя данные в дочерней таблице видны те же самые, что перед этим:

SQL> select d.*, m.* from td4 d left join tm m on d.pid = m.id;

          ID          PID           ID
============ ============ ============
           1            1            1
           2        <null>        <null>

SQL> alter table td4 add constraint td4_fk foreign key(pid) references tm(id);
SQL> commit;
SQL>

Вышеприведенное означает, что и вот это тоже не заработает:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
set autoddl off;
commit; 
set transaction read committed;
set term ^;
execute block as begin
  in autonomous transaction do
  execute statement 'update td4 d set pid = null where not exists(select * from tm m where m.id = d.pid)';

  execute statement 'alter table td4 add constraint td4_fk foreign key(pid) references tm(id) on delete set null';
end
^
set term ;^
commit; -- вот тут будет облом, "Problematic key value is ("PID" = NULL)"
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040527
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоид,

FK строит индекс, а индекс видит все версии, актуальные на текущий момент. То же самое будет, если на столбце с дубликатами строить ПК - даже если удалить дубликаты, ПК не построится до тех пор, пока удаленные дубликаты не будут убраны как мусор.
Или, если в одной транзакции удалить запись, а в другой попытаться добавить запись с тем же ПК. Еще лучше это иллюстрируется при отключении сборки мусора в коннекте и алгоритме с "переиспользованием" идентификаторов ПК.
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040539
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
afgmМожет ближе к идеалу в Оракле? Я не совсем в теме этой СУБД, но галка
валид/невалид пытается угодить обоим подходам?
Галка "инвалид" в Оракуле это архитектурный костыль для нетранзакционного DDL.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040579
micis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
hvladmicisПросто мне хотелось использовать один блок, потому что в нём я в начале сохраняю состояние проверок (процедура возвращает 0 или 1), выключаю проверки, делаю эти самые изменения и в конце проверки активирую как было. Может подскажете как можно это всё реализовать по-другому?Первый раз в этой теме вижу слово "проверки". Что это такое - не знаю и сам придумывать не буду.
Так что пока что ничего подсказать просто не могу.Вот реальный текст блока:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
execute block
as
DECLARE tbl varchar(50);
declare check_patient integer;
begin
  execute procedure check_constraint_status('CHK_DOC_INFO_PATIENT_ID') returning_values (:check_patient);
  execute procedure MODIFY_CONSTRAINT_STATUS('DOC_INFO', 'CHK_DOC_INFO_PATIENT_ID', 0);

  for select trim("TABLE") from doc_types t, rdb$relations n where t."TABLE"=n.rdb$relation_name
  into :tbl do begin
    in autonomous transaction do begin
      execute statement 'update '||tbl||' set PATIENT_ID=NULL where PATIENT_ID not in (select ID from PATIENT)';
    end
    in autonomous transaction do begin
      execute statement 'ALTER TABLE '||tbl||' ADD CONSTRAINT FK_'||tbl||'_P FOREIGN KEY (PATIENT_ID) REFERENCES PATIENT(ID)';
    end
  end

  execute procedure MODIFY_CONSTRAINT_STATUS('DOC_INFO', 'CHK_DOC_INFO_PATIENT_ID', :check_patient);
end;
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040590
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Hello, Micis!
You wrote on 1 сентября 2015 г. 14:32:58:

Micisset PATIENT_ID=NULL where PATIENT_ID not in (select ID from PATIENT)
этот кусок нужно выполнять с блокированием таблицы
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040699
Таблоид
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kdvFK строит индекс, а индекс видит все версии, актуальные на текущий момент. Это понятно, но версии эти созданы были в той же самой транзакции, что пытается установить FK. И поэтому откат к прежней версии (нарушающей условие FK) будет означать также отмену оператора 'alter table ... add constraint <FK>'. Тут перестраховка какая-то, КМК...
...
Рейтинг: 0 / 0
Проблемы с созданием foreign key и предварительной очисткой данных
    #39040708
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблоидно версии эти созданы были в той же самой транзакции, что пытается установить FK.
update создает к текущей версии новую версию, и по возможности чистит ненужные предыдущие. Создание индекса тоже чистит версии.
Однако, у тебя в сценарии есть сессия #2, которая стартовала ДО update, соответственно, старые версии удерживаются для нее, и ты сам же пишешь, что после облома и commit в сессии #2 как раз все начинает работать.
Так что - были версии, не давали создать ФК. версии стали мусором - убрались, не мешают создать ФК.
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Проблемы с созданием foreign key и предварительной очисткой данных
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]