Без справочников не обходится ни одна информационная система. Как правило, такие справочники представлены в виде одной либо нескольких таблиц, иногда связанных между собой. Одной из проблем является "неполнота" данных, когда справочник не заполнен по определенным позициям.

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

Пример подобной структуры:

|Id | ParentId | Name | Value | ,

где ParentId — ссылка на вышестоящий узел.

Глубина иерархии такого справочника не ограничена, так‑же возможно неограниченное разветвление дерева.

Рассмотрим справочник адресов почты сотрудников предприятия.

Id

ParentId

Name

Value

1

null 

Предприятие

Наше предприятие

2

1

E-mail 

factory@mail.ru

Условный запрос вида Get({Предприятие=»Наше предприятие»}, E‑mail) выдаст значение «factory@mail.ru».

Добавим узел дерева справочника — Подразделение=»Отдел ИТ» и к нему еще один узел

E‑mail=”it@mail.ru”

Теперь запрос Get({Предприятие=»Наше предприятие», Подразделение=»Отдел ИТ»}, E‑mail) выдаст значение «it@mail.ru». Однако, если нет узла «Подразделение», либо значение не заполнено — значение будет взято из вышестоящего узла.

Если добавить узел дерева «Служба поддержки» и значение support@mail.ru со ссылкой на узел «Подразделение»=»Отдел ИТ» — получим адрес службы поддержки, если он не существует — адрес отдела, и так далее выше по иерархии.

Таким образом получаем структуру справочника, который выдает значение «всегда».

Второй пример — интернационализация приложения.

Для интернационализации приложения предлагается следующий подход:

  • в базе данных хранятся значения Caption и Hint для всех компонентов, используемых в приложении;

  • при запуске приложения они считываются из БД и заполняются соответствующие свойства компонентов;

  • для получения значения Caption и Hint запрос к БД делается в виде: Application.Form.Component.Property.Origin;

  • для хранения Caption и Hint используется иерархическая структура справочника, который выдает значение «всегда», если нет значения в запрашиваемом узле справочник — будет выдано значение из вышестоящего уровня иерархии. Глубина иерархии такого справочника не ограничена, так‑же возможно неограниченное разветвление дерева.

Пример: Запрос Get(Application.Form1.Component2.Property3) выдаст значение из узла «Application», если нет значений для нижестоящего уровня иерархии, выдаст значение из узла «Form1» — если есть значение для этого уровня иерархии, и так далее.

Таким образом можно, например, ввести значение Caption=»Поиск» для кнопки с Origin=»Find» для всего приложения, но для кнопки на форме «Form2» — использовать значение «Искать», а для кнопки «btnFindAll» — - использовать значение «Искать везде».

Такой способ существенно экономит место в БД, так как хранится всего одно общее значение и исключения от него.

Структура таблицы:

CREATE TABLE t_caption_ru (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
  parent_id INT NULL DEFAULT '0',
  owner VARCHAR(255) NOT NULL, 
  origin VARCHAR(255) NOT NULL, 
  caption VARCHAR(255) NOT NULL, 
  hint VARCHAR(255) NOT NULL, 
  INDEX Индекс 1 (id) 
) 
ENGINE=InnoDB 
AUTO_INCREMENT=1;

Запрос для получения данных:

SET @origin='Find';
SET @LEVEL1='Application';
SET @LEVEL2='Form1';
SET @LEVEL3='btnFind';
/* Выдает первое значение, которое не NULL, то есть значение будет всегда, 
но с разных уровней иерархии */
SELECT COALESCE(t3.caption, t2.caption, t1.caption)
FROM t_caption_ru t1
LEFT JOIN t_caption_ru t2 ON (t2.parent_id=t1.id AND t2.owner @LEVEL22)
LEFT JOIN t_caption_ru t3 ON (t3.parent_id=t2.id AND t3.owner @LEVEL33)

WHERE
(t1.owner = @LEVEL1 AND t1.origin = @origin) or
(t2.origin = @origin) or
(t3.origin = @origin)

Комментарии (4)


  1. dopusteam
    00.00.0000 00:00

    Однако, если нет узла "Подразделение", либо значение не заполнено - значение будет взято из вышестоящего узла

    Как понять, вернулось запрашиваемое значение или родительское?

    который всегда возвращает значение

    Что если справочник вообще пустой или нет никакого родителя? Тогда значение не вернётся, а значит - значение возвращается не всегда


    1. yumata Автор
      00.00.0000 00:00
      -1

      Ну это-же "мысли по-поводу", а не готовое приложение...

      Можно добавить значение по-умолчанию можно еще много чего.


  1. KirmiziTas
    00.00.0000 00:00
    +1

    Глубина иерархии такого справочника не ограничена

    Тогда нужен не COALESCE а рекурсивный запрос.


  1. Naf2000
    00.00.0000 00:00
    +2

    1. Моделей иерархии в РСУБД достаточно много, указанная Вами - самая простая в реализации, но возможно не самая оптимальная в эксплуатации. http://www.codenet.ru/db/other/trees/

    2. Всегда ли надо заменять на более "общую" информацию? Пример иерархии Предприятие - Отдел - Сотрудник. Вы запрашиваете адрес сотрудника, а получаете адрес подразделения или предприятия, запрашиваете ИНН сотрудника - получаете ИНН предприятия, где он работает. Мне кажется это будет даже хуже, чем отсутствие информации.