(no subject)
Apr. 18th, 2005 11:56 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Будучи связан с базами данных по долгу службы в течение последних 7 лет,
постоянно задумываюсь об отсутствии в них многих полезных вещей. Все они
либо ни с какого бока не относятся к реляционной модели данных, либо
противоречат ей, что,собственно говоря, и является причиной отсутствия этих
вещей на уровне базы и необходимости каждый раз делать их заново.
Первая из таких вещей - отсутствие в описаниях полей и таблиц упоминания
о том, что их вообще-то редактируют пользователи. Которые любят понятные
сообщения об ошибках, а не "Foreign key "FK_UserEditedFieldRefToOtherTable"
violation". Любят справочники, из которых так удобно доставать эти самые
значения внешних ключей. Любят названия полей на родном языке и с пробелами
в них. Любят поля для редактирования с форматированием, куда гораздо труднее
ввести неправильное значение.
Соответственно, вводится таблица FieldDescs стиля вроде:
TABLE_NAME
FIELD_NAME
USER_FIELD_NAME
FORMAT
VIEW_WIDTH
REFTABLE
итд,
заполняется и таскается с собой вместе с инсталлятором/дампом базы. Обрабатывается
при отображении заголовков полей в экранных таблицах и при редактировании.
----------
Вторая вещь достаточно спорная и заимствована из идеи о объектных базах данных.
Это наследование структуры записей. Т.е. мы имеем, к примеру, две таблицы
tbl0
Field0,
Field1,
Field2
и
tbl1
Field0,
Field1,
Field2,
Field3,
Field4
при этом вторая таблица фактически расширяет первую двумя дополнительными полями.
Каждой записи из второй таблицы соответствует запись в первой.
Эту часть можно имитировать с помощью нескольких таблиц, в каждой из которых
будут только уникальные для данного типа записей поля и первичный ключ, по которому
они связываются. Тогда получить все записи определенного типа и унаследованных от него,
можно, обратившись в запросе к его таблице.
select tbl0.id, tbl0.Field0,tbl0.Field1,tbl0.Field2,tbl1.Field3,tbl1.Field4
from tbl0
left join tbl1 on tbl1.id=tbl0.id
в данном случае печаль в том, что добавление объекта требует заполнения
всех таблиц в которые попадают его части и установки первичного ключа
во всех таблицах.
Второй вариант- дублировать поля во всех унаследованных таблицах, а получать
записи типа и его потомков с помощью union, который бы объединял выборки из
таблицы типа и потомков. Запись каждого типа находится только в одной таблице.
select tbl0.Field0,tbl0.Field1,tbl0.Field2
from tbl0
union
select tbl1.Field0,tbl1.Field1,tbl1.Field2
from tbl1
тут будет проблема с поиском объекта по заданному первичному ключу - либо отдельно
хранить таблицу с типом объекта, который определяет в какой он таблице живет, либо
перебирать все таблицы. Кроме этого, будет дублироваться код сохранения полей объекта
для каждой таблицы.
А хотелось бы, чтобы при выборке из одной таблицы это выглядело как множество
объектов базового типа, соответствующего этой таблице. И чтобы первичный ключ
был один. И чтобы код сохранения одного поля объекта был только один раз.
---------
Третья часть - версионность записей и история их изменений
Некоторые сервера используют версионность внутри для реализации параллельного чтения-записи
данных, сохраняя старые версии измененных записей, если есть транзакция которой они еще
нужны на предмет чтения.
Но дело в том, что часто версионность и история изменений нужна и на пользовательском уровне.
Даже реализовав систему разграничения доступа к записям и разрешив менять записи только строго
определенным пользователям - у них возникает вопрос "А какое значение в этой записи было вчера?".
Поэтому приходится реализовывать историю изменений и хранение версий самому, как минимум частично
повторяя существующую функциональность сервера.
А еще есть такая вещь, как изменения задним числом в бухгалтерии. Мрачная печаль, хотелось бы заметить.
Изменение одной записи иногда тянет за собой каскад изменений других и методику адекватной
реализации подобного каскада с расчетом переходов(корректировочных проводок, прокладываемых сейчас
для учета исправления ошибки несколько месяцев назад) между двумя деревьями зависимых записей
(тем, которое было, и исправленным) я до сих пор представляю с трудом. Максимум, что мне приходит в
голову, это представить все это дело как многомерный массив, индексами в котором будут последовательности
аналитических кодов, рассчитать дважды и вычесть один массив из другого.
постоянно задумываюсь об отсутствии в них многих полезных вещей. Все они
либо ни с какого бока не относятся к реляционной модели данных, либо
противоречат ей, что,собственно говоря, и является причиной отсутствия этих
вещей на уровне базы и необходимости каждый раз делать их заново.
Первая из таких вещей - отсутствие в описаниях полей и таблиц упоминания
о том, что их вообще-то редактируют пользователи. Которые любят понятные
сообщения об ошибках, а не "Foreign key "FK_UserEditedFieldRefToOtherTable"
violation". Любят справочники, из которых так удобно доставать эти самые
значения внешних ключей. Любят названия полей на родном языке и с пробелами
в них. Любят поля для редактирования с форматированием, куда гораздо труднее
ввести неправильное значение.
Соответственно, вводится таблица FieldDescs стиля вроде:
TABLE_NAME
FIELD_NAME
USER_FIELD_NAME
FORMAT
VIEW_WIDTH
REFTABLE
итд,
заполняется и таскается с собой вместе с инсталлятором/дампом базы. Обрабатывается
при отображении заголовков полей в экранных таблицах и при редактировании.
----------
Вторая вещь достаточно спорная и заимствована из идеи о объектных базах данных.
Это наследование структуры записей. Т.е. мы имеем, к примеру, две таблицы
tbl0
Field0,
Field1,
Field2
и
tbl1
Field0,
Field1,
Field2,
Field3,
Field4
при этом вторая таблица фактически расширяет первую двумя дополнительными полями.
Каждой записи из второй таблицы соответствует запись в первой.
Эту часть можно имитировать с помощью нескольких таблиц, в каждой из которых
будут только уникальные для данного типа записей поля и первичный ключ, по которому
они связываются. Тогда получить все записи определенного типа и унаследованных от него,
можно, обратившись в запросе к его таблице.
select tbl0.id, tbl0.Field0,tbl0.Field1,tbl0.Field2,tbl1.Field3,tbl1.Field4
from tbl0
left join tbl1 on tbl1.id=tbl0.id
в данном случае печаль в том, что добавление объекта требует заполнения
всех таблиц в которые попадают его части и установки первичного ключа
во всех таблицах.
Второй вариант- дублировать поля во всех унаследованных таблицах, а получать
записи типа и его потомков с помощью union, который бы объединял выборки из
таблицы типа и потомков. Запись каждого типа находится только в одной таблице.
select tbl0.Field0,tbl0.Field1,tbl0.Field2
from tbl0
union
select tbl1.Field0,tbl1.Field1,tbl1.Field2
from tbl1
тут будет проблема с поиском объекта по заданному первичному ключу - либо отдельно
хранить таблицу с типом объекта, который определяет в какой он таблице живет, либо
перебирать все таблицы. Кроме этого, будет дублироваться код сохранения полей объекта
для каждой таблицы.
А хотелось бы, чтобы при выборке из одной таблицы это выглядело как множество
объектов базового типа, соответствующего этой таблице. И чтобы первичный ключ
был один. И чтобы код сохранения одного поля объекта был только один раз.
---------
Третья часть - версионность записей и история их изменений
Некоторые сервера используют версионность внутри для реализации параллельного чтения-записи
данных, сохраняя старые версии измененных записей, если есть транзакция которой они еще
нужны на предмет чтения.
Но дело в том, что часто версионность и история изменений нужна и на пользовательском уровне.
Даже реализовав систему разграничения доступа к записям и разрешив менять записи только строго
определенным пользователям - у них возникает вопрос "А какое значение в этой записи было вчера?".
Поэтому приходится реализовывать историю изменений и хранение версий самому, как минимум частично
повторяя существующую функциональность сервера.
А еще есть такая вещь, как изменения задним числом в бухгалтерии. Мрачная печаль, хотелось бы заметить.
Изменение одной записи иногда тянет за собой каскад изменений других и методику адекватной
реализации подобного каскада с расчетом переходов(корректировочных проводок, прокладываемых сейчас
для учета исправления ошибки несколько месяцев назад) между двумя деревьями зависимых записей
(тем, которое было, и исправленным) я до сих пор представляю с трудом. Максимум, что мне приходит в
голову, это представить все это дело как многомерный массив, индексами в котором будут последовательности
аналитических кодов, рассчитать дважды и вычесть один массив из другого.
no subject
Date: 2005-05-04 04:01 pm (UTC)Некоторые сервера используют версионность внутри для реализации параллельного чтения-записи
данных, сохраняя старые версии измененных записей, если есть транзакция которой они еще
нужны на предмет чтения.
Но дело в том, что часто версионность и история изменений нужна и на пользовательском уровне.
Даже реализовав систему разграничения доступа к записям и разрешив менять записи только строго
определенным пользователям - у них возникает вопрос "А какое значение в этой записи было вчера?".
Поэтому приходится реализовывать историю изменений и хранение версий самому, как минимум частично
повторяя существующую функциональность сервера.
А еще есть такая вещь, как изменения задним числом в бухгалтерии. Мрачная печаль, хотелось бы заметить.
Изменение одной записи иногда тянет за собой каскад изменений других и методику адекватной
В 90-ом году написал на Clipper 5 движок, который реализовывал обе задачи - т.е. журналирование и была возможна корректировка записей в двух режимах - внесение очередных изменений (по ним можно было вытаскивать историю) и исправление ошибок задним числом. Когда выпустил бету (писалось всё под конкретную аппликуху), решил, что пойду повешусь от полноты пережитых чувств.
Релиз так и не был выпущен, в связи с переводом проекта на CodeBase.
адекватной
реализации подобного каскада с расчетом переходов(корректировочных проводок, прокладываемых сейчас
для учета исправления ошибки несколько месяцев назад) между двумя деревьями зависимых записей
(тем, которое было, и исправленным) я до сих пор представляю с трудом. Максимум, что мне приходит в
голову, это представить все это дело как многомерный массив, индексами в котором будут последовательности
аналитических кодов, рассчитать дважды и вычесть один массив из другого.
Так вот, логическим было показана, что задача в общем виде не решабельна. Есть несколько различных методов - их приходится отруливать вручную на основе свободного волеизлеяния бухгалтера.