Реляционный дизайн: атрибуты столбца - PullRequest
4 голосов
/ 01 июля 2011

У меня есть система, которая позволяет человеку выбрать тип формы, который он хочет заполнить из выпадающего списка.Из этого показываются остальные поля для этой конкретной формы, пользователь заполняет их и отправляет запись.

Таблица форм:

| form_id | age_enabled | profession_enabled | salary_enabled | name_enabled |

Здесь описываются метаданные формы, чтобы система знала, как ее нарисовать.Таким образом, каждый столбец _enabled имеет логическое значение true, если форма должна содержать поле, которое необходимо заполнить для этого столбца.

Таблица ввода:

| entry_id | form_id | age | profession | salary | name | country |

Здесь хранится отправленная форма.Если возраст, профессия и т. Д. Хранит действительное значение, заполненное в форме (или ноль, если его не было в форме)

Пользователи могут добавлять новые формы в систему на лету.

Теперь главный вопрос: я хотел бы добавить возможность для пользователя, проектирующего новую форму, иметь возможность включать список возможных значений для атрибута (например, профессия - это выпадающий список, скажем, 20 профессий).вместо просто текстового поля при заполнении формы).Я не могу просто сохранить глобальный список возможных значений для каждого столбца, потому что у каждой формы будет свой список значений для выбора.

Единственное решение, которое я могу придумать, - это включить в таблицу форм еще один набор столбцов, например professional_values, а затем сохранить значения в формате с разделителями символов.Я обеспокоен тем, что однажды столбец может иметь большое количество возможных значений, и этот столбец выйдет из-под контроля.

Обратите внимание, что новые столбцы могут быть добавлены позже в форму, если это необходимо (и, следовательно, ввод по очереди), но 90% форм имеют одинаковый базовый набор столбцов, поэтому я думаю, что этот дизайн лучше, чем дизайн EAV,Мысли?

Я никогда не видел реляционный дизайн для такой системы (в целом), и я не могу найти приличный способ сделать это.

Ответы [ 2 ]

4 голосов
/ 01 июля 2011

Я думаю, что вы начинаете не с того места.

| form_id | age_enabled | profession_enabled | salary_enabled | name_enabled |

Собираетесь ли вы продолжать добавлять в эту таблицу все поля, которые вы когда-либо имели?Обычно список может быть бесконечным.

Как код вашего приложения отобразит форму, если все поля в столбцах этой таблицы?

А как насчет таблицы формы, подобной этой:

| form_id | form description |

Затем другая таблица, formAttributes с одной строкой на запись в форме:

| attribute_id | form_id | position | name | type | 

Затем третья таблица дляAttributeValidValues ​​с одной строкой на атрибут действительное значение:

| attribute_id | value_id | value |

Для начала это может показаться большим трудом, но на самом деле это не так.Подумайте о том, как легко добавить или удалить новый атрибут или значение в форме.Также подумайте о том, как ваше приложение будет отображать форму:

for form_element in (select name, attribute_id 
                     from formAttributes 
                     where form_id = :bind
                     order by position asc) loop
  render_form_element
  if form_element.type = 'list of values' then
     render_values with 'select ... from formAttributeValidValues'
  end if
end loop;

Затем возникает дилемма, как хранить результаты формы.В идеале вы должны хранить их по 1 строке на элемент формы в таблице, которая выглядит примерно так:

| completed_form_id | form_id | attribute_id | value |

Если вы когда-либо работаете только с одной формой за раз, тогда эта модель будет работать хорошо.Если вы хотите выполнить агрегирование по множеству форм, то результирующие запросы становятся более сложными, однако это отчеты, которые могут выполняться в процессе, отличном от записи в онлайн-форме.Вы можете начать думать о вещах, которые сводят запросы для преобразования строк в столбцы или материализованное представление для объединения форм одного типа и т. Д.

4 голосов
/ 01 июля 2011

Создайте новую таблицу, которая будет содержать группы значений:

CREATE TABLE values (
    id SERIAL,
    group INT NOT NULL,
    value TEXT NOT NULL,
    label TEXT NOT NULL,
    PRIMARY KEY (id),
    UNIQUE (group, value)
);

Например:

INSERT INTO values (group, value, label) VALUES (1, 'NY', 'New York');
INSERT INTO values (group, value, label) VALUES (1, 'CA', 'California');
INSERT INTO values (group, value, label) VALUES (1, 'FL', 'Florida');

Итак, группа 1 содержит три возможных значения для вашего раскрывающегося селектора.Затем ваша таблица форм может ссылаться на то, какую группу использует конкретный столбец.

Обратите также внимание, что вы должны добавлять поля в форму с помощью строк, а не столбцов.Т.е. ваше приложение не должно корректировать схему при добавлении новых форм, оно должно только создавать новые строки.Итак, сделайте каждое поле отдельной строкой:

CREATE TABLE form (
    id SERIAL,
    name TEXT NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE form_fields (
    id SERIAL,
    form_id INT NOT NULL REFERENCES form(id),
    field_label TEXT NOT NULL,
    field_type INT NOT NULL,
    field_select INT REFERENCES values(id),
    PRIMARY KEY (id)
);

INSERT INTO form (name) VALUES ('new form');
$id = last_insert_id()
INSERT INTO form_fields (form_id, field_label, field_type) VALUES ($id, 'age', 'text');
INSERT INTO form_fields (form_id, field_label, field_type) VALUES ($id, 'profession', 'text');
INSERT INTO form_fields (form_id, field_label, field_type) VALUES ($id, 'salary', 'text');
INSERT INTO form_fields (form_id, field_label, field_type, field_select) VALUES ($id, 'state', 'select', 1);
...