Я бы пошел с подходом сообщений. Это лучший способ обеспечить ссылочную целостность.
Если вам нужны дополнительные столбцы для Ответов и Вопросов соответственно, поместите их в дополнительные таблицы с отношением один к одному с сообщениями.
Например, в синтаксисе MySQL:
CREATE TABLE Posts (
post_id SERIAL PRIMARY KEY,
post_type CHAR(1), -- must be 'Q' or 'A'
-- other columns common to both types of Post
UNIQUE KEY (post_id, post_type) -- to support foreign keys
) ENGINE=InnoDB;
CREATE TABLE Comments (
comment_id SERIAL PRIMARY KEY,
post_id BIGINT UNSIGNED NOT NULL,
-- other columns for comments (e.g. date, who, text)
FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB;
CREATE TABLE Questions (
post_id BIGINT UNSIGNED PRIMARY KEY,
post_type CHAR(1), -- must be 'Q'
-- other columns specific to Questions
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
) ENGINE=InnoDB;
CREATE TABLE Answers (
post_id BIGINT UNSIGNED PRIMARY KEY,
post_type CHAR(1), -- must be 'A'
question_id BIGINT UNSIGNED NOT NULL,
-- other columns specific to Answers
FOREIGN KEY (post_id, post_type) REFERENCES Posts(post_id, post_type)
FOREIGN KEY (question_id) REFERENCES Questions(post_id)
) ENGINE=InnoDB;
Это называется наследованием таблиц классов. В этой статье представлен хороший обзор моделирования наследования с помощью SQL: « Наследование в реляционных базах данных .» *
Может быть полезно использовать post_type, чтобы данное сообщение могло содержать только один ответ или один вопрос. Вы не хотите, чтобы ответ и вопрос ссылались на один данный пост. Такова цель столбца post_type
выше. Вы можете использовать ограничения CHECK, чтобы применить значения в post_type
, или использовать триггер, если ваша база данных не поддерживает ограничения CHECK.
Я также сделал презентацию, которая может вам помочь. Слайды на http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back. Вы должны прочитать разделы о Полиморфных Ассоциациях и Entity-Attribute-Value.
Если вы используете наследование отдельных таблиц, как вы сказали, что используете Ruby on Rails, то SQL DDL будет выглядеть так:
CREATE TABLE Posts (
post_id SERIAL PRIMARY KEY,
post_type CHAR(1), -- must be 'Q' or 'A'
-- other columns for both types of Post
-- Question-specific columns are NULL for Answers, and vice versa.
) ENGINE=InnoDB;
CREATE TABLE Comments (
comment_id SERIAL PRIMARY KEY,
post_id BIGINT UNSIGNED NOT NULL,
-- other columns for comments (e.g. date, who, text)
FOREIGN KEY (post_id) REFERENCES Posts(post_id)
) ENGINE=InnoDB;
В этом примере вы можете использовать ограничение внешнего ключа, и я рекомендую вам это сделать! : -)
Философия Rails способствует внедрению модели данных на прикладном уровне. Но без ограничений, обеспечивающих целостность в базе данных, вы рискуете, что ошибки в вашем приложении или специальные запросы из инструмента запросов могут нанести ущерб целостности данных.