2016-08-11 5 views
0

У меня есть следующие основные структуры таблицыMySQL: Нормализация типы контента, категорий и подкатегорий

  • Содержание

    • ID
    • TYPE_ID (FK для ContentType)
    • category_id (с нулевым значением для категории FK)
    • sub_category_id (обнуляемым FK в подкатегорию)
  • ТипСодержимого

    • ID
  • Категория

    • ID
    • content_type_id (FK для ContentType)
  • подкатегорию

    • ID
    • category_id (FK Категория)

Важно, чтобы категория контента соответствовала его типу.

Аналогично, подкатегория контента должна соответствовать ее категории.

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

Как я могу изменить структуру таблицы для защиты от этого? Или я должен придерживаться логики приложения?

SCHEMA ПО ТРЕБОВАНИЮ

CREATE TABLE `content_type` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) 

CREATE TABLE `category` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `content_type_id` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_category_content_type` FOREIGN KEY (`content_type_id`) REFERENCES `content_type` (`id`), 
) 

CREATE TABLE `sub_category` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `category_id` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_sub_category_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`), 
) 

CREATE TABLE `content` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
 `type_id` int(10) unsigned NOT NULL, 
 `category_id` int(10) unsigned DEFAULT NULL, 
 `sub_category_id` int(10) unsigned DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    CONSTRAINT `fk_content_type` FOREIGN KEY (`type_id`) REFERENCES `content_type` (`id`), 
    CONSTRAINT `fk_content_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) 
    CONSTRAINT `fk_content_sub_category` FOREIGN KEY (`sub_category_id`) REFERENCES `sub_category` (`id`) 
) 
+0

Прежде всего, если у вас есть подкатегории, вы должны связать их со своим родителем, поэтому в таблице подкатегорий вы должны добавить поле для родительской категории. Во-вторых, неясно, что вы подразумеваете под ** нормализацией **. – FDavidov

+0

В соответствии с логикой приложения это то, для чего предназначены хранимые процедуры/функции. – FDavidov

+0

@FDavidov не уверен, что вы имеете в виду .. есть поле category_id для родительской категории в SubCategory. – Arth

ответ

1

В таблице категорий создайте уникальный индекс (id, content_type_id). В таблице SubCategory создайте уникальный индекс (id, category_id).

Затем в содержимое таблицы, создавать ФКС, как это:

constraint FK_ContentCategory foreign key(category_id, type_id) 
    references Category(id, content_type_id) 

constraint FK_ContentSubCategory foreign key(sub_category_id, category_id) 
    references SubCategory(id, category_id) 

В ФКС в категории и подкатегории таблиц остаются прежними.

Поскольку подкатегория зависит от категории, которая зависит от типа содержимого, сделайте ссылки FK отражать одну и ту же цепочку зависимостей. Теперь, когда вы вводите type_id в таблице Content, значения категории и подкатегории должны принадлежать правильной цепочке зависимостей.

Однако, если вам когда-либо понадобится изменить тип записи содержимого, вы должны сначала сменить category_id и sub_category_id на NULL, изменить type_id, а затем вставить правильные значения в категории_id и sub_category_id. Небольшая цена за целостность данных.

+0

Не был полностью уверен, что отдельно 'NULL'able' category_id' и 'subcategory_id' будут хорошо воспроизводиться в этих двух перекрывающихся составных FK .. поэтому в итоге было создано еще две таблицы HAS_ONE' content_category (content_id, content_type_id, category_id) 'и' content_sub_category (content_id, category_id, sub_category_id) '.. где не было проблем с' NULL' и аналогичными FK. Поскольку основная идея была из вашего ответа, и она отлично поработала бы без «NULL», я соглашусь! Благодаря :) – Arth

1

В MySQL вы можете добавить только основные ограничения. Вы не можете добавить условные ограничения (хотелось бы видеть это).

В качестве альтернативы вы могли бы скомпоновать проверки в ПЕРЕД ВСТАВЛЕНИИ/ОБНОВЛЕНИИ.И использовать СИГНАЛ отменить INSERT/UPDATE (см https://dev.mysql.com/doc/refman/5.5/en/signal.html)

ТВЕН Я думаю, что это может стать правдой проблемы, если у вас есть системы «третьи сторонние» говорит непосредственно в базу данных. Если нет, вы можете решить это в своем приложении. логики и создавать API для стороннего доступа.

Если вы действительно хотите решить эту проблему на уровне РСУБД, вы можете взглянуть на PostgreSQL (через CHECK).

ПРИМЕЧАНИЕ. Что касается таблиц категорий, я бы рассмотрел, добавив родительский элемент и сохранил его в одной таблице (самозависимость). Это позволило бы вставить вашу категорию на второй уровень.

Смежные вопросы