Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > БД в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 29.09.2008, 05:37   #1
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию "not null" и триггер в IBase/FB

Всем доброе время суток.
В ходе работы с СУБД InterBase/FireBird столкнулся со следующей структурой таблицы:
Поле-идентификатор(ключ) таблицы - integer и not null, все отлично это гарантирует наличие значения для каждой записи, но не уникальность значений. Для ключевого поля также есть триггер(ну и генератор), гарантирующие - наличие значения + его уникальность!

Такая структура видимо правильна но мне не удобна поскольку не позволяет сделать AppendRecord.
Очень хочется убрать not null, т.к. триггер(+генератор) важнее.

В связи с этим вопрос:

Считаю что для ключевого поля можно не ставить ограничение not null если для этого поля уже есть триггер на BeforeInsert.
Ведь сам факт обработки события "перед вставкой" записи гарантирует что значение в поле будет, + генератор дает автоинкремент т.е. уникальность.

Правильно ли я рассуждаю?
Каквы мнения участников форму на данный счет?
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Старый 29.09.2008, 15:06   #2
Andrei
Форумчанин
 
Регистрация: 20.06.2007
Сообщений: 270
По умолчанию

А если кто-то впоследствии удалит это значение во время редактирования?
-Кукушка, кукушка! Накукуй мне сто лет!
-А накукуй тебе столько?

(с) Библия. Вольный перевод с древнееврейского.
Andrei вне форума Ответить с цитированием
Старый 29.09.2008, 16:09   #3
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Для ключевого поля без not null неполучится. Правило Not null для ключевых полей зашито в систему и требуется обязательно.
А что за проблема с AppendRecord???

Последний раз редактировалось Rik; 29.09.2008 в 16:11.
Rik вне форума Ответить с цитированием
Старый 01.10.2008, 05:32   #4
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию

Цитата:
Сообщение от Andrei Посмотреть сообщение
А если кто-то впоследствии удалит это значение во время редактирования?
А кто ж даст пользователю такую возможность? Даже если значение поля будет отображаться то оно будет нередактируемым.

Цитата:
Сообщение от Rik Посмотреть сообщение
Для ключевого поля без not null неполучится. Правило Not null для ключевых полей зашито в систему и требуется обязательно.
А что за проблема с AppendRecord???
Неправильно выразился - я не ставлю такое поле как primary key. Оно по сути своей является ключом, уникальным идентификатором записи.

При попытке вызвать процедуры вставки или добавления (Insert/Append) новой пустой записи появляется сообщение о том что это поле должно иметь значение, но если при вставке явно задаю значение также появляется ошибка. Да и мое мнение и мнение генератора по этому значению могут разойтись . И генератор дает значение до меня - триггер же висит на событие BeforeInsert. И тогда добавление возможно только по SQL запросу INSERT. Такой запрос меня напрягает - полей в таблице много, нужно много писанины и выше вероятность ошибки.
Но вот если не ставить not null то все нормально - добавляются записи, и я могу проходить все поля по их индексам и присваивать значения в цикле.
Такой путь оказался очень удобным при копировании записей из .mdb таблицы в IB с одинаковыми полями.
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Старый 01.10.2008, 06:26   #5
Andrei
Форумчанин
 
Регистрация: 20.06.2007
Сообщений: 270
По умолчанию

Цитата:
Сообщение от Surgeon Посмотреть сообщение
А кто ж даст пользователю такую возможность? Даже если значение поля будет отображаться то оно будет нередактируемым.
Но вы можете оказаться не единственным программистом, кто захочет воспользоваться созданной вами базой данных. Вы можете заболеть, уйти в отпуск или заниматься в это время другим проектом, или вообще уйти с этого предприятия. Да мало ли что. Другой человек может не знать или не обратить внимания на подобные тонкости, или, наконец, просто схалтурить.

Сама БД и интерфейс работы с ней, IMHO, разные вещи. Поэтому, если есть возможность обеспечить целостность БД средствами сервера БД, я предпочитаю по максимуму использовать их.
-Кукушка, кукушка! Накукуй мне сто лет!
-А накукуй тебе столько?

(с) Библия. Вольный перевод с древнееврейского.

Последний раз редактировалось Andrei; 01.10.2008 в 11:52.
Andrei вне форума Ответить с цитированием
Старый 02.10.2008, 23:27   #6
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Цитата:
При попытке вызвать процедуры вставки или добавления (Insert/Append) новой пустой записи появляется сообщение о том что это поле должно иметь значение, но если при вставке явно задаю значение также появляется ошибка.
Что-то вы неправильно делаете... Задача проста, всего-навсего обеспечить одно поле уникальным значением, неважно как, лишь бы к моменту сохранения записи, там значение уникальное было. Лучший вариант, значение брать из генератора. Даже если 10000... человек будут вставлять запись одновременно, генератор обеспечит уникальность значения. Генерацию вы можете делать в триггере, хранимой процедуре или вообще на стороне клиента, как вам удобнее... Обычно никаких сложностей и ошибок с этим не возникает.
Цитата:
Да и мое мнение и мнение генератора по этому значению могут разойтись . И генератор дает значение до меня - триггер же висит на событие BeforeInsert. И тогда добавление возможно только по SQL запросу INSERT. Такой запрос меня напрягает - полей в таблице много, нужно много писанины и выше вероятность ошибки.
А как без INSERT вы вставляете записи в базу? Даже если вы и используете какое либо техническое средство, оно все равно вызывает Insert, тока вы этого незамечаете. И имеющиеся триггеры срабатывают всегда. Напрягаться не надо, если у вас с запросами туго, IBExpert автоматом сгенерит любую конструкцию и никакой писанины делать не надо, IBExpert все зделает за вас.
Цитата:
Но вот если не ставить not null то все нормально - добавляются записи, и я могу проходить все поля по их индексам и присваивать значения в цикле.
Такой путь оказался очень удобным при копировании записей из .mdb таблицы в IB с одинаковыми полями.
По правилам создания реляционных баз данных, таблица должна иметь первичный ключ. Технически, ваш вариант конечно возможен, но SQL сервера в первую очередь расчитаны на сетевую многопользовательскую работу. До тех пор пока вы все эти операции делаете монопольно, ничего страшного не произойдет, но представте, несколько человек будут работать с такой таблицей, в котором непостоянно значение ключа и возможен null, крах неменуем.

Последний раз редактировалось Rik; 02.10.2008 в 23:37.
Rik вне форума Ответить с цитированием
Старый 03.10.2008, 05:44   #7
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию

Цитата:
Сообщение от Andrei Посмотреть сообщение
Но вы можете оказаться не единственным программистом, кто захочет воспользоваться созданной вами базой данных. Вы можете заболеть, уйти в отпуск или заниматься в это время другим проектом, или вообще уйти с этого предприятия. Да мало ли что. Другой человек может не знать или не обратить внимания на подобные тонкости, или, наконец, просто схалтурить.
Кхм-м, я и есть "не единственный" :). Кажется 4 или 5-ый кто поддерживает этот проект.
Цитата:
Сообщение от Andrei Посмотреть сообщение
Сама БД и интерфейс работы с ней, IMHO, разные вещи. Поэтому, если есть возможность обеспечить целостность БД средствами сервера БД, я предпочитаю по максимуму использовать их.
Если правильно понял - not null нужно использовать, так безопаснее.

Цитата:
Сообщение от Rik Посмотреть сообщение
Что-то вы неправильно делаете... Задача проста, всего-навсего обеспечить одно поле уникальным значением, неважно как, лишь бы к моменту сохранения записи, там значение уникальное было. Лучший вариант, значение брать из генератора. Даже если 10000... человек будут вставлять запись одновременно, генератор обеспечит уникальность значения. Генерацию вы можете делать в триггере, хранимой процедуре или вообще на стороне клиента, как вам удобнее...
Да вот это я ипытаюсь уточнить - на мой взгляд связка триггер на "Before Insert" и генератор обеспечат уникальность. В целом это реализация автоинкрементного типа которого у IB нет.
Значение из генератора берет за меня сервер БД при выполнении компонентом IBTable процедуры Append, затем я заполняю остальные поля.
Цитата:
Сообщение от Rik Посмотреть сообщение
Обычно никаких сложностей и ошибок с этим не возникает.
Вот на это я и надеюсь.
Цитата:
Сообщение от Rik Посмотреть сообщение
А как без INSERT вы вставляете записи в базу?
Примерно так:
...
IBTable.Append:
IBTable.FieldByName[FIELDNAME].Value:=XXX;
for i:=y to z do
begin
IBTable.Fields.Field[i].Value:=ADOTable.Fields.Field[(i+a)].Value;
end;
...
Смысл в том что я обхожу циклом все 30-40 полей и обращаюсь по их индексу. При этом происходит импорт из адошной таблицы с похожей структурой. Т.Е. 10-20 полей подряд одинаковые и я их значения забираю не используя обращение по имени, только по индексу поля.

Цитата:
Сообщение от Rik Посмотреть сообщение
Даже если вы и используете какое либо техническое средство, оно все равно вызывает Insert, тока вы этого незамечаете.
Да я это понимаю. Но как реализовать в зарпосе например перебор всех полей не зная их по именам? ( т.е. не привязываясь к структуре таблицы)
А вот такой перебор дает эту возможность если я знаю что есть несколько одинаковых полей у двух наборов данных .
Цитата:
Сообщение от Rik Посмотреть сообщение
И имеющиеся триггеры срабатывают всегда.
На это я и рассчитываю, но тогда считаю not null избыточностью.
Цитата:
Сообщение от Rik Посмотреть сообщение
Напрягаться не надо, если у вас с запросами туго, IBExpert автоматом сгенерит любую конструкцию и никакой писанины делать не надо, IBExpert все зделает за вас.
Но это надо делать для каждого набора данных отдельно.
Цитата:
Сообщение от Rik Посмотреть сообщение
По правилам создания реляционных баз данных, таблица должна иметь первичный ключ. Технически, ваш вариант конечно возможен, но SQL сервера в первую очередь расчитаны на сетевую многопользовательскую работу. До тех пор пока вы все эти операции делаете монопольно, ничего страшного не произойдет, но представте, несколько человек будут работать с такой таблицей, в котором непостоянно значение ключа и возможен null, крах неменуем.
Стоп,стоп,стоп... Как это соотносится с вашим предыдущим высказыванием? :
Цитата:
Сообщение от Rik Посмотреть сообщение
всего-навсего обеспечить одно поле уникальным значением, неважно как, лишь бы к моменту сохранения записи, там значение уникальное было. Лучший вариант, значение брать из генератора. Даже если 10000... человек будут вставлять запись одновременно, генератор обеспечит уникальность значения.
Цитата:
Сообщение от Rik Посмотреть сообщение
По правилам создания реляционных баз данных, таблица должна иметь первичный ключ.
В итоге если правильно понял - not null нужно использовать, так правильнее.
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Старый 03.10.2008, 07:55   #8
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Цитата:
Сообщение от Surgeon Посмотреть сообщение
Стоп,стоп,стоп... Как это соотносится с вашим предыдущим высказыванием?
На сколько я понял, вы добавляете записи, в которых идентификатор записи вообще отсутствует и вы потом его подставляете. Теперь представте, вы записи добавили, а идентификатор туда добавить не успели и у вас 1000 записей с идентификатором NULL, за это время, другой пользователь выбрал записи и попытался удалить всего навсего одну запись без идентификатора. С его клиента уйдет запрос на удаление следующего вида: DELETE FROM MyTable WHERE IDRECORD = NULL. Как вы думаете, сколько записей удалится? Правильно, все те, в которые вы не успели подставить значение.
Другой момент, возникнет ситуация, когда вы не сможете подставить идентификатор по такому способу. Если нет идентификатора записи, как сервер узнает, в какую запись нужно подставить этот самый идентификатор? Рано или поздно возникнет момент, когда вы попытаетесь пронумеровать одну запись, а уникальный идентификатор, пропишется сразу в несколько записей и уникальным уже не будет, скорее всего, эта беда уже с вами случилась, а без not null и уникального индекса вы её и не заметили. Затем, при попытке отредактировать или удалить такую запись, у вас одновременно отредактируются или удалятся не одна, а все записи у которых совпал идентификатор.
На счет генератора. Представте, два пользователя одновременно добавляют запись, не используя генератор. Они выяснили, что последняя запись была 1000, и они оба свои записи пронумеровали как 1001 и в результате в базу добавилось две записи с номером 1001, не имея уникального индекса на ключевое поле, сервер это всё пропустит. Генератор же обеспечит уникальность, сколько бы пользователей к нему не обращалось одновременно.

На всех нормальных SQL серверах нет автоинкрементных полей, для этого существуют последовательности, в IB/FB они называются генераторы, счас их тоже переименовали в последовательности...
Rik вне форума Ответить с цитированием
Старый 03.10.2008, 08:51   #9
Rik
Форумчанин
 
Аватар для Rik
 
Регистрация: 28.07.2007
Сообщений: 361
По умолчанию

Surgeon
Видимо я вас неправильно понял, но совершенно ясно одно, с ключевыми полями лучше не эксперементировать, это все придумано не вчера и всё проверено временем. На ключевое поля не только not null надо но и primary key.

Последний раз редактировалось Rik; 03.10.2008 в 08:56.
Rik вне форума Ответить с цитированием
Старый 04.10.2008, 06:05   #10
Surgeon
Форумчанин
 
Регистрация: 04.10.2007
Сообщений: 106
По умолчанию

Цитата:
Сообщение от Rik Посмотреть сообщение
На сколько я понял, вы добавляете записи, в которых идентификатор записи вообще отсутствует и вы потом его подставляете.
Не совсем так - запись доавляется но при этом идентификатор заполняется средствами сервера БД, т.е. триггер+генератор.
Цитата:
Сообщение от Rik Посмотреть сообщение
Теперь представте, вы записи добавили, а идентификатор туда добавить не успели и у вас 1000 записей с идентификатором NULL,
Эта ситуация невозможна, т.к .триггер на событии BeforeInsert.

Цитата:
Сообщение от Rik Посмотреть сообщение
На счет генератора. Представте, два пользователя одновременно добавляют запись, не используя генератор. Они выяснили, что последняя запись была 1000, и они оба свои записи пронумеровали как 1001 и в результате в базу добавилось две записи с номером 1001, не имея уникального индекса на ключевое поле, сервер это всё пропустит. Генератор же обеспечит уникальность, сколько бы пользователей к нему не обращалось одновременно.
Я понимаю зачем нужна связка триггер+генератор.
Цитата:
Сообщение от Rik Посмотреть сообщение
На всех нормальных SQL серверах нет автоинкрементных полей, для этого существуют последовательности, в IB/FB они называются генераторы, счас их тоже переименовали в последовательности...
Да я знаю, но смысл тот же, только Access где есть автоинкремент наверное скрывает этот контроль внутри себя.
========
Еще раз:
я предлагаю сравнить следующие ситуации и цепочки событий:

1.Есть триггер на BeforeInsert+ генератор.
Когда я вызываю IBTable.Append на сервер БД уходит команда на вставку записи.
Сервер обрабатывает событие BeforeInsert, т.е. еще до реального добавления записи запрашивает значение генератора и заносит в соответствующее поле записи. Т.е. уже обеспечивает уникальность идентификатора.
Затем я заполняю остальные поля данной записи.
Затем уже IBTable.Post и после добавления нужного числа записей
IBTransaction.CommitRetaining.

2.Есть триггер на BeforeInsert+ генератор, и поле-идентифкатор объявлено как not null.
Когда я вызываю IBTable.Append на сервер БД уходит команда на вставку записи.
Вот тут вылетает ошибка что поле не может быть null.
Отсюда я делаю вывод что проверка на not null сервером БД осуществляется раньше чем присваевается значение из генератора!
Если же я буду выполнять IBTable.AppendRecord(IDValue,Field1 Value...FieldNValue), т.е в процедуре сразу присваивать значения полям записи включая поле-идентификатор, то значение поля-идентификатора будет конфликтовать со значением взятым из генератора.

3.Есть триггер на BeforeInsert+ генератор, и поле-идентифкатор объявлено как not null.
Вызывается выполнение запроса с текстом типа : 'insert into mytable ....'
Вот что происходит дальше в этом варианте я не совсем понимаю потому что ошибок не генерируется, значит значение из генератора закидывается до проверки на not null?
====
Так вот в связи с этими варантами я интересуюсь :
- почему не прокатывает 2,
- как срабатывает 3-ий
- чем плох 1-ый (мне нравится)

Т.е при любом раскладе используется триггер+генератор, так что меня за их использование не надо агитировать, я и так "за!".
Все не так плохо, как вам кажется, на самом деле все гораздо хуже.
http://delphiworld.narod.ru/dw.html - 5000 статей!!! удобный поиск, оффлайн сборник, рекомендую всем
Surgeon вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Ошибка при использовании OlePropertyGet("Documents").OleProcedure("Add") в C++ Builder AleksP C++ Builder 7 11.04.2009 13:06
если пользователь наберет какой-то другой символ не "y" или "n" и нажмет enter, программа проигнорирует skobets Общие вопросы C/C++ 2 03.06.2008 06:51
Excel файл открывается не "до конца" (странички "не показываются" только серое поле) Dorvir Microsoft Office Excel 2 28.03.2008 10:03
Создаю диаграмму "Bar". Подскажите как убрать растояние между "столбами" MAcK Компоненты Delphi 11 24.10.2007 10:49
На чем пишутся стратегии типа "Казаков" и "Эпохи империи" Tayfun Свободное общение 3 26.06.2007 20:27