Дмитрий Малюгин где-то в 2001
|
70-е годы прошедшего века. В Органы приходит мужик и говорит:
У меня для вас есть потрясающая идея!
Выкладывай.
Представьте себе такой прибор с кнопками, на которых написано: Вашингтон, Лондон, Париж. Нажимаешь на кнопку взрывается Вашингтон, нажимаешь на другую взрывается Лондон.
Здорово! А как этот прибор сделать?
Ну, мужики, это не ко мне, я даю идею, остальное дело техники
|
Введение.
Целью данной работы является обсуждение свойств некоторых объектов метаданных платформы
«1С:Оперативный учет». Будут предложены пути "повышения концептуального
единства" текущей версии платформы (далее V7), которые должны облегчить и
упорядочить процесс создания устойчивых информационных систем.
Среди множества предложений по улучшению функциональных свойств V7 были выбраны те,
которые, на наш взгляд, наиболее важны с концептуальной точки зрения:
- Обсуждение свойств «базового агрегатного объекта». Объединение свойств
объектов Таблица значений и Запрос
в объекте Таблица данных.
- Группы элементов. Организация и поддержка иерархии кортежей.
- Повышение уровня абстракции объекта Регистр до
фундаментального понятия Функциональная зависимость.
- Включение в платформу понятия Роли объектов.
Среди перечисленных пунктов нет таких "набивших оскомину" предложений как, к примеру,
"увеличение количества табличных частей документа" или "даёшь ООП в V7".
Первый выглядит довольно тривиальным, а второй недостаточно четко определенным (аморфным)
для обсуждения в рамках статьи.
Зачастую автор испытывал затруднения с использованием соответствующей материалу терминологии.
В ряде мест пришлось вводить новые термины, возможно, не всегда удачные, что могло сказаться
на четкости выражения мыслей. Где-то изложенному не хватает строгости и подробностей, но
написание книги не являлось целью работы. Автор рассчитывает на терпение читателей и
соответствующий уровень подготовки.
I. Таблицы данных (ТД). Группировка кортежей.
Общие свойства таблиц данных.
Почему мы начинаем обсуждение с таблиц? Потому что данное понятие является базовым
(абстрактным) в теории БД. В конечном счете, выходные данные получают обычно в виде неких
таблиц, что достаточно удобно. Как известно, версия 7.5 платформы не поддерживала понятие
Таблица Значений, но в версии 7.7 данный объект "под давлением
обстоятельств" пришлось ввести. Поскольку понятие было "введено задним числом", возникли
определенные нестыковки с уже имеющимися понятиями V7.
Забудем на время про те объекты, которые используются в V7, и зададимся вопросом, какими
свойствами должна обладать абстрактная Таблица Данных (не путать
с таблицей значений)? Для начала стандартными свойствами таблиц, состоящих из
набора кортежей. Вспомним основные свойства:
- Колонки таблицы (называемые также реквизитами, атрибутами, полями) определяют тип
значений, хранящихся в ячейках таблицы.
- Строки таблицы в общем случае неупорядочены (поэтому мы используем термин "кортеж",
а не "строка таблицы").
- Тип значений ячеек определяется для каждой колонки таблицы в целом. Значением ячейки
может быть "ссылка на объект агрегатного типа".
- Не допускаются два и более идентичных кортежа (должны слиться в один).
- Следствием свойства (2) является набор процедур навигации по таблице:
- встать в начало/конец таблицы
- перейти к следующему/предыдущему кортежу (удобны также коронные
ВыбратьКортежи() и ПолучитьКортеж()
)
- найти кортеж (кортежи), значения которого удовлетворяют определенным условиям.
- Прочие важные свойства: сортировать кортежи, найти итог какой-либо коммутируемой
функции по всем значениям колонки (например, сумму чисел), свернуть кортежи, отфильтровать
таблицу, создать новую таблицу на основе данной и каких-либо условий, слить две таблицы в
одну, сохранить таблицу в файл, загрузить из файла, редактировать. И так далее.
Какие-то из перечисленных свойств Таблиц Данных (ТД)
реализованы в Таблице Значений, какие-то можно (нужно) эмулировать.
Мы же обратимся к рассмотрению операций группировки ТД.
Группировка кортежей.
В V7 есть два объекта (Таблица Значений и
Запрос) для манипулирования с одним и тем же с выборкой
данных. Это не выглядит логичным. Более того, процедуры навигации различны, в запросе это
цикличный обход группировок, а в таблице значений перебор строк. Не правильнее
ли будет сократить число сущностей?
Для начала разберемся с группировками. Конечно, "группировка" не очень удачный термин
(особенно в свете того, что в V7 есть перпендикулярное понятие "группы элементов" в
справочниках). Возможно, что правильнее было бы использовать термин "упорядочивание". Но
тогда необходимо заменить используемый в V7 оборот "упорядочить по:" на "сортировать по:",
что может привести к еще большей путанице, так что потерпим "группировку".
Итак, вводим понятие Группировки Кортежей в таблице данных. Под
группировкой кортежей по какой-либо колонке мы понимаем упорядочивание кортежей по
какому-либо критерию, заданному для значений данной колонки.
Каким же образом после группировки появляются "циклы обхода группировок"? Дело в том,
что группировка ТД по какой-либо колонке разбивает исходную ТД на ТД-владельца,
в которой есть группирующая колонка с уникальными значениями (а также, возможно, некоторые
"итоговые" колонки), и на подчиненные ей таблицы с неупорядоченными кортежами (в которых
группирующая колонка, разумеется, отсутствует).
Каждая из подчиненных таблиц, в свою очередь, также может быть сгруппирована по какой-либо
из оставшихся колонок, образуя новые связи "один ко многим" и т.д.
Поясним сказанное на примере. Пусть мы имеем на входе неупорядоченную таблицу данных ТД1:
AB |
CD |
NUM |
a |
c |
1 |
a |
d |
2 |
b |
c |
3 |
b |
d |
3 |
a |
c |
2 |
a |
c |
3 |
Исходная таблица данных ТД1
После группировки таблицы ТД1 по столбцу AB с добавлением итогов по колонке NUM получаем
три таблицы таблицу-владельца с двумя кортежами (A, 8) и (B, 4),
а также подчиненные данным элементам неупорядоченные таблицы:
|
AB = A |
CD |
NUM |
c |
1 |
d |
2 |
c |
2 |
c |
3 |
|
|
ТД1, сгруппированная по столбцу AB.
|
Подчиненные таблицы можно также группировать по следующему столбцу (CD), получая уже
второй уровень подчиненности и т.д. Наверное, не помешает будет также операция отмены
группировки для возврата к исходной таблице, после чего можно группировать в другом порядке.
Отметим, что теперь операции навигации по подчиненным таблицам невозможны без
позиционирования на каком-либо кортеже таблицы-владельца AB. Это и есть "обход группировок"
в терминах V7. Как известно, только после вызова метода
Группировка() можно получить значения таблицы в группирующих
колонках. Более правильным будет сохранить обычную терминологию таблиц для выборки кортежей.
Тем более что в общем случае группировка может быть осуществлена совместно по нескольким
колонкам. Например, после группировки ТД1 по AB+CD (не путать с группировкой по AB, а затем
по CD) с включением итогов по NUM получим:
AB |
CD |
E NUM |
a |
c |
6 |
a |
d |
2 |
b |
с |
3 |
b |
d |
1 |
|
|
|
|
|
ТД1, сгруппированная совместно по столбцам AB и CD.
|
Таким образом, при выполнении группировки исходной таблицы (рассматриваем только один уровень)
необходимо указать:
- Перечень колонок, по которым выполняется группировка;
- Перечень дополнительных (например, итоговых) колонок;
Идентификатор группировки.
На последнем пункте остановимся подробнее. Необходимость присваивания группировке отдельного
идентификатора вытекает хотя бы из того факта, что в одной группировке может участвовать
несколько колонок. С другой стороны после выполнения операции "группировка" свойства
таблицы меняются. Теперь операции навигации относятся не к исходной таблице, а к получившейся
таблице-владельцу. В то же время, после позиционирования на каком-либо кортеже
таблицы-владельца можно выполнять операции навигации по подчиненной таблице.
Для того, чтобы указать, что операция применяется именно к подчиненной таблице и нужен
идентификатор группировки.
Поясним сказанное на примере таблицы ТД1. Пусть изначально ТД1 свободна от группировок.
Тогда позиционирование на первой записи (с помощью метода
ТД1.ВстатьВНачало()) даст кортеж со значениями
{ ТД1.AB=a, ТД1.CD=c, ТД1.NUM=1 }
Сгруппируем ТД1 по колонке AB (включая итоги по NUM) и дадим группировке имя грAB.
Метод может выглядеть примерно так:
ТД1.Группировать("грAB", "AB",
"SumNUM=Итог(NUM)").
Теперь метод ТД1.ВстатьВНачало() даст кортеж
{ ТД1.AB=a, ТД1.SumNUM=8 }
Значения колонок CD и NUM не определены. Однако после позиционирования на кортеже
таблицы-владельца есть возможность навигации по подчиненной таблице
ТД1.грAB.ВстатьВНачало() даст кортеж
{ ТД1.грAB.CD=c, ТД1.грAB.NUM=1 }
Следующий уровень группировки можно применять к предыдущему, например:
ТД1.грAB.Группировать("грCD", "CD", "SumNUM=Итог(NUM)").
После двух таких группировок доступ к атрибуту "NUM" возможен только через три точки
(ТД1.грAB.грCD.NUM) и только после позиционирования на
кортежах всех таблиц-владельцев.
Достоинство приведенного определения операции группировки в том, что операция замкнута, то
есть в результате ее выполнения мы получаем просто еще один объект типа
Таблица Данных. Это позволяет выполнять рекурсивные вызовы
операций, организовывать циклы и т. д. Более того, на наш взгляд, ничто не препятствует
тому, чтобы на одном уровне группирования организовывать группировки разных типов. То есть,
применительно к нашему примеру, допускается сосуществование группировок
ТД1.грAB1 и ТД1.грAB2,
сгруппированных по одной и той же колонке AB. При этом подчиненные
таблицы (тип и идентификаторы колонок) данных группировок могут быть различны.
Аналог существование нескольких справочников, подчиненных одному владельцу, или
документов с несколькими табличными частями.
Важный момент заключается также в том, что группировка может производиться не только "вниз",
но и "вверх". Допустим, мы имеем колонку в ТД со ссылками на товары, и каждый из товаров
имеет реквизит "Производитель". Мы можем (или мягче должны иметь возможность)
сгруппировать данную ТД по производителям товаров. При выполнении такой операции к ТД
добавляется колонка "Производитель", а текущая ТД преобразуется в подчиненную
ТД.Производитель.
При обсуждении группировок уместно вспомнить о необходимости введения в платформу понятий
Интервал (временной и числовой) и Набор
Интервалов. Это сделает возможным операцию группировки по значениям типа
"Число" и "Дата". Концепция интервалов отдельная тема, которой мы еще коснемся
при обсуждении оборотных ресурсов функциональных зависимостей.
Проецирование объектов агрегатного типа в Таблицу Данных
Объект ТД является наиболее низшим в иерархии объектов агрегатного типа, следовательно,
любой другой объект должен иметь процедуры проецирования (отображения, выгрузки) в таблицу
данных. Кроме того, существующие в V7 независимые сущности Запрос
и Таблица значений должны слиться в одно понятие
Таблица данных. Результатом выполнения запроса должна быть ТД,
а уж сгруппированная или нет определяется текстом запроса.
Рассмотрим операции выгрузки объектов в ТД.
- Выгрузка справочников. В простейшем случае одноуровневого справочника он проецируется в
ТД без особых проблем. Набор реквизитов справочника определяет колонки ТД и их тип, а
элементы справочника это просто кортежи ТД. Если справочник имеет подчиненный
справочник, то операция проецирования такого справочника должна обеспечить возможность
создания ТД, сгруппированной по колонкам-реквизитам справочника-владельца.
Наверное, должна быть предусмотрена и обратная процедура заполнение
справочников на основе ТД.
- Выгрузка документов (журналов). Опять же для документов без табличной части имеем
плоскую ТД, а для документов с табличной частью (или несколькими ТЧ)
сгруппированную ТД. Движения документа проецируются в плоскую ТД.
- Выгрузка регистров (функциональных зависимостей). Естественно все должно выгружаться в
ТД как состояние регистров (итоги), так и изменения состояний (движения).
- Выгрузка перечислений. Может оказаться полезной. Особенно если дать возможность для
объекта Перечисление определять его набор реквизитов.
- Выгрузка отчетов и обработок. Шутка ;-). Тем не менее, очень часто
результаты отчетов/обработок удобно представлять в виде таблицы значений, следовательно,
тем более удобно будет делать это в форме ТД.
При обсуждении выгрузки справочников мы обошли вниманием два тонких момента: что делать с
группами элементов справочника, и как выгружаются периодические реквизиты справочников.
Первый вопрос рассматривается в следующей главе, второй в главе
"Функциональные зависимости".
Резюме.
- Объекты V7 Таблица значений и Запрос
должны быть заменены одним базовым понятием Таблица
данных.
- Таблицы данных могут быть подчинены друг другу.
- Соотношениями подчиненности управляет "группировка" колонок таблиц. Группировка
ТД может осуществляться как "вниз", так и "вверх".
- Все объекты агрегатного типа должны уметь выгружаться (проецироваться) в ТД.
|