Страница 1 из 1

Не проходит commit в процедуре

Добавлено: 23 дек 2008, 18:07
john_chek
Вот процедура:

Код: Выделить всё

begin
select max(tk.TYEAR) from type_kart tk
into :YEAR_ID;
DT = 'now';
tek_year = extract(year from DT);
if (year_id <> tek_year) then
 begin
 insert into type_kart(id)
 values(gen_id(gen_type_kart_id,1));
 nomer = gen_id(gen_kart_nomer_vhod, -gen_id(gen_kart_nomer_vhod,1))+1;
 end
else
 begin
 nomer = gen_id(gen_kart_nomer_vhod,1);
 end
suspend;
end
Insert не проходит, где поставить Commit, чтобы не ругался?

Re: Не проходит commit в процедуре

Добавлено: 23 дек 2008, 19:44
armagedon2007
Commit в ПО делать надо а не в процедуре.

Re: Не проходит commit в процедуре

Добавлено: 23 дек 2008, 21:06
WildSery
john_chek писал(а):Вот процедура:
Ужас-ужас.
john_chek писал(а):

Код: Выделить всё

nomer = gen_id(gen_kart_nomer_vhod, -gen_id(gen_kart_nomer_vhod,1))+1;
Что за фигня?
Прочитай статью про генераторы.

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 09:18
john_chek
WildSery , это не фигня уважаемый, ты ведь не знаешь, что здесь и зачем(это не генератор первичного ключа вовсе), поэтому в таких коментах не нуждаюсь, лучше вопрос читай.
Эта процедура раздает номера входящим документам и ежегодно обнуляет(до единицы) нумератор, и добавляет в таблицу новый период счисления!
Поэтому сначало код разбери, а потом комментируй!

Тему можно запостить, задача решена, спс! :)

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 10:40
armagedon2007

Код: Выделить всё

nomer = gen_id(gen_kart_nomer_vhod, -gen_id(gen_kart_nomer_vhod,1))+1;
Если у тебя это делает генеранор = 0 то зачем его увеличивать на 1 полчать -1 и пибавлять 1.
достаточно

Код: Выделить всё

nomer = gen_id(gen_kart_nomer_vhod, -gen_id(gen_kart_nomer_vhod,0));

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 10:51
john_chek
john_chek писал(а):nomer = gen_id(gen_kart_nomer_vhod, -gen_id(gen_kart_nomer_vhod,0));
Нет так получится nomer = 0, а нужно чтобы nomer = 1.
Можно было и по другому сделать, не спорю, но как сразу в голову пришло так и сделал. Можно не увеличивать на 1, согласен, это не доглядел

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 11:01
WildSery
john_chek писал(а):WildSery , это не фигня уважаемый, ты ведь не знаешь, что здесь и зачем(это не генератор первичного ключа вовсе), поэтому в таких коментах не нуждаюсь, лучше вопрос читай.
Не указывай, что для меня лучше, ведь за мои ответы ты не платишь. :wink:
Что хочу, то и пишу, а обоснованность написанного пусть модератор рассудит.
Вопрос я прочитал, и он указывает на весьма поверхностные знания как по генераторам, так и по транзакциям.

Теперь собственно "ответы".
1. В единицу генератор выставляют обычно так: nomer = gen_id(gen_kart_nomer_vhod, 1-gen_id(gen_kart_nomer_vhod, 0));.
Сделав nomer = GEN + 1, ты выставил генератор в 0, а значение получил 1. Следующее чтение генератора даст опять 1. Т.е. два первых будут. Но это ещё цветочки.
3. Судя по возникшей проблеме (невозможность вставки второго такого же года) процедура запускается не монопольно, что вкупе с использованием генератора делает её ошибочной. Не будет она правильно номера выдавать в самом начале года, выдаст номер "1" всем (почти)одновременно запросившим клиентам, до коммита первого из них.

Эта задача решаема, но по-другому. А так как ты, задав вопрос, нетерпим к здоровой критике, то и решение попробуй составить самостоятельно. По крайней мере, без моего участия.

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 11:21
john_chek
WildSery писал(а):В единицу генератор выставляют обычно так: nomer = gen_id(gen_kart_nomer_vhod, 1-gen_id(gen_kart_nomer_vhod, 0));.
Сделав nomer = GEN + 1, ты выставил генератор в 0, а значение получил 1. Следующее чтение генератора даст опять 1. Т.е. два первых будут. Но это ещё цветочки.
- с этим согласен, действительно мой косяк
WildSery писал(а):Судя по возникшей проблеме (невозможность вставки второго такого же года) процедура запускается не монопольно
здесь не согласен ! А зачем собственно мне вставлять второй такой же год??, я встявляю новый год, а хоть процедура и не монопольная, в её начале идет select, кот. выбирает max(Год), и пускай хоть все вместе запустят процедуру(кто-то же запустит её раньше :wink: ). Добавится новый год, обновится нумератор и все получат свои номера.
А указывать я тебе ничего не собирался, если обидел извини, просто изначально вопрос не о работе процедуры был! Будь здоров!

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 11:54
WildSery
john_chek писал(а):А зачем собственно мне вставлять второй такой же год??
Прежде чем спорить, прочитай про транзакции раздел "обязательное чтение". Особенно, что касается видимости версий.
john_chek писал(а):я встявляю новый год, а хоть процедура и не монопольная, в её начале идет select, кот. выбирает max(Год), и пускай хоть все вместе запустят процедуру(кто-то же запустит её раньше :wink:
Если ты прочитаешь указанные ссылки, тебе станет ясно, что "второй" select max() не увидит нового вставленного года из "первого" запуска той же процедуры, пока она не будет завершена по commit, и будет считать себя "первой".
Именно поэтому у тебя и вылазит PK constraint violation (или у тебя уникальный индекс?) при попытке вставить вторую запись с тем же самым годом.

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 12:11
john_chek
WildSery писал(а):не увидит нового вставленного года из "первого" запуска той же процедуры, пока она не будет завершена по commit
Все давным давно прочитано... это верно, но ведь транзакцию я выполняю программно, после каждого insert в датасете:

Код: Выделить всё

  dm.StoredProc.ExecProc;
  dm.BDKart.FieldByName('nomer_vhod').Value := dm.StoredProc.FieldValue('nomer', true);
  dm.StoredProc.Transaction.CommitRetaining;
  dm.StoredProc.Close;
Хотя есть загвоздка, что новый номер, в "первый" раз вставится в предыдущий год, но я думаю обработать это событие программно?! просто не давать регистрировать документы в старый год (если наступил новый) и предлагать выбрать др. период, а потом уже генерить номер
Именно поэтому у тебя и вылазит PK constraint violation (или у тебя уникальный индекс?)
в таблице периодов кроме PK индекса ID, больше нет индексов, там есть еще поля, но их заполняет триггер перед вставкой, в том числе и поле TYear, которое хранит год.

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 12:26
WildSery
john_chek писал(а):Все давным давно прочитано...
Значит, не понято.
john_chek писал(а):но ведь транзакцию я выполняю программно, после каждого insert в датасете:
Но ведь программу ты запускаешь не в единственном экземпляре.

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

Re: Не проходит commit в процедуре

Добавлено: 24 дек 2008, 12:32
john_chek
Можно и так, в любом случае спасибо тебе за советы :)