Подтвердить что ты не робот

Как я могу обрабатывать разные типы данных в проекте Entity-Attribute-Value (например, одна таблица с несколькими столбцами или несколькими таблицами для каждого типа данных)?

Я хочу создать таблицу метаданных пациента/образца, используя подход с атрибутом-атрибутом (EAV).

Вопрос. Как мне обрабатывать переменный тип столбца значения (например, строковый, числовой или внешний ключ в таблице словаря) на основе атрибута?

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

Репрезентативные данные

Пациент/образец (сущность) может иметь несколько атрибутов метаданных (например, местоположение лаборатории, выживаемость, тип опухоли), каждый из которых имеет другой тип значения (например, VARCHAR, NUMBER, FOREIGN_KEY *, соответственно).

* FOREIGN_KEY означает, что этот тип значения представляет собой идентификатор внешнего ключа (INTEGER) для таблицы значений словаря (например, список из 10 возможных типов опухолей). Поэтому местоположение лаборатории может быть VARCHAR, так как я не забочусь о нормализации этих значений. Но тип опухоли должен иметь некоторую степень валидации.

Моя таблица может выглядеть примерно так:

CREATE TABLE patients (
  patient_id INTEGER CONSTRAINT pk_patients PRIMARY KEY,
  patient_name VARCHAR2(50) NOT NULL
);

CREATE TABLE metadata_attributes (
  attribute_id INTEGER CONSTRAINT pk_metadata_attributes PRIMARY KEY,
  attribute_name VARCHAR2(50) NOT NULL,
  attribute_value_type VARCHAR(50) NOT NULL -- e.g. VARCHAR, NUMBER, or ID
);

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value ???
);

Мне кажется, нужен столбец определения типа значения (attribute_value_type) в таблице metadata_attributes, чтобы узнать, какой столбец/таблицу следует искать.

Возможные подходы

Вот два возможных подхода, о которых я могу думать.

Подход 1: Отдельная таблица EAV с несколькими столбцами

Создайте три разных столбца в таблице patient_metadata - по одному для каждого типа значений.

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_varchar_value VARCHAR(50),
  attribute_number_value NUMBER,
  attribute_id_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id)
);

Подход 2: несколько таблиц EAV

Создайте три разные таблицы patient_metadata - по одному для каждого типа значений.

CREATE TABLE patient_metadata_varchar (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value VARCHAR(50) NOT NULL
);

CREATE TABLE patient_metadata_number (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value NUMBER NOT NULL
);

CREATE TABLE patient_metadata_id (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id) NOT NULL
);

Другие подходы?

Существуют ли другие подходы?

Короче говоря, я хочу как можно больше уважать реляционную целостность и позволять базе данных знать тип значения, чтобы он мог выполнять базовую проверку. Тем не менее, я считаю, что оба вышеупомянутых подхода потребуют некоторых проверок проверки целостности вручную (для подхода 1 требуется проверка того, что заполняется только один столбец attribute_value и т.д.).

Типы запросов, которые я буду выполнять, будут типичными (например, получить список значений для данного атрибута метаданных, получить список значений для данного пациента (объекта) и атрибута метаданных и т.д.). Я считаю, что в большинстве случаев мне нужно будет запросить тип значения, чтобы узнать, какой столбец или таблица запрашивать. Любой другой путь вокруг этого?

Каковы плюсы и минусы для всех подходов (производительность, структура запросов и т.д.)?

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

4b9b3361

Ответ 1

Это хорошо известная проблема. Проблема с упомянутым вами подходом заключается в том, что вам нужно знать тип атрибута перед тем, как вы его запросите. это не конец света, потому что вы управляете метаданными, но все же...

Возможны два возможных решения:

  • с использованием типа данных varchar2 для представления всех типов данных в известном формат. Числа и символы не являются проблемой, значения даты могут быть записаны в предопределенном виде (это как реализация to_String() в любом OO дизайн).
  • используйте ANYDATA тип данных. я лично играл с ним, но решил не использовать он.

Ответ 2

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

С небольшим вниманием вы можете поддерживать порядок сортировки, если это имеет значение (например, по датам форматирования как год/месяц/день), и валидация типов не должна выполняться базой данных в любом случае, поскольку слишком поздно. Отрицательные числа - это боль, как и поплавков, но очень необычно индексировать число, которое может быть отрицательным или поплавка, а виды в памяти обычно бывают быстрыми.

Если тип данных не является очевидным или должен быть известен процессору ниже по потоку, добавьте столбец типа.

Как правило, все ограничения целостности по значениям столбцов могут быть проверены до того, как запись будет записана либо в коде (хорошем), либо в триггерах (не очень хорошо). Попытка использовать встроенные функции с различными типами приведет вас к пока что, и, вероятно, не так полезна, так как значения часто имеют множество ограничений для бизнеса в любом случае, например. дата рождения должна быть не нулевой и после 1900 года.

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

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

Наконец, в настоящее время такие данные просто не сохраняются в стиле реляционной базы данных, ориентированных на столбцы. Он обычно хранится как документ XML (или JSON) (типы XML в Oracle), и большинство баз данных предоставляют некоторые собственные возможности обработки XML для поиска и обработки таких данных. Это нормально для нормального хранения и поиска формы, но имеет тенденцию делать произвольные запросы, такие как "дать мне всех пациентов старше 60 лет, у которых была пневмония в прошлом году", довольно медленная или немного более активная, так как требуется обратная индексация с метками. Тем не менее, стоит посмотреть, является ли подход, ориентированный на документ/текст, лучшим решением.

Удачи!