Diseño de base de datos: artículos, publicaciones en blogs, fotos e historias

Estoy diseñando una base de datos para un sitio web que tendrá al menos 4 tipos de objetos diferentes representados (artículos, publicaciones en blogs, fotos, historias), cada uno de los cuales tiene requisitos de datos suficientemente diferentes para garantizar sus propias tablas. Queremos que los usuarios puedan publicar comentarios para cualquiera de estos tipos. Los requisitos de datos para los comentarios son simples e independientes del tipo de cosas que el comentario considera (es decir, solo un cuerpo de comentario y el correo electrónico del autor).

Quiero evitar la redundancia de crear y administrar 4+ tablas separadas para los comentarios, por lo que me gustaría poder mantener todos los comentarios en una tabla, posiblemente especificando la relación a través de 2 columnas: una para designar la entidad padre y otra para la Id. de fila primaria

pero no entiendo cómo, entonces, implementaría claves externas, ya que las claves externas establecen una relación entre 2 y solo 2 tablas (¿verdad?).

Entonces, con todo eso en mente, ¿cuál sería el mejor enfoque?

Esta es una forma de implementar tablas de supertipo / subtipo para su aplicación.

Primero, la tabla de supertipos. Contiene todas las columnas comunes a todos los subtipos.

CREATE TABLE publications ( pub_id INTEGER NOT NULL PRIMARY KEY, pub_type CHAR(1) CHECK (pub_type IN ('A', 'B', 'P', 'S')), pub_url VARCHAR(64) NOT NULL UNIQUE, CONSTRAINT publications_superkey UNIQUE (pub_id, pub_type) ); 

A continuación, un par de tablas de subtipo.

 CREATE TABLE articles ( pub_id INTEGER NOT NULL, pub_type CHAR(1) DEFAULT 'A' CHECK (pub_type = 'A'), placeholder CHAR(1) NOT NULL, -- placeholder for other attributes of articles PRIMARY KEY (pub_id, pub_type), FOREIGN KEY (pub_id, pub_type) REFERENCES publications (pub_id, pub_type) ); CREATE TABLE stories ( pub_id INTEGER NOT NULL, pub_type CHAR(1) DEFAULT 'S' CHECK (pub_type = 'S'), placeholder CHAR(1) NOT NULL, -- placeholder for other attributes of stories PRIMARY KEY (pub_id, pub_type), FOREIGN KEY (pub_id, pub_type) REFERENCES publications (pub_id, pub_type) ); 

Las restricciones CHECK () y FOREIGN KEY en estas tablas de subtipo impiden que las filas hagan referencia al tipo incorrecto de fila en el supertipo. Efectivamente particiona los valores de pub_id entre los subtipos, lo que garantiza que cualquier pub_id dado puede aparecer en una y solo una de las tablas de subtipo. Es por eso que necesita una restricción PRIMARY KEY o NOT NULL UNIQUE en el par de columnas {publications.pub_id, publications.pub_type}.

La tabla para comentarios es simple. Dado que tiene la misma estructura para todos los subtipos, puede hacer referencia al supertipo.

 CREATE TABLE comments ( pub_id INTEGER NOT NULL REFERENCES publications (pub_id), comment_timestamp TIMESTAMP NOT NULL DEFAULT now(), commenter_email VARCHAR(10) NOT NULL, -- Only allow people who have -- really short email addresses comment_text VARCHAR(30) NOT NULL, -- Keep 'em short! PRIMARY KEY (pub_id, comment_timestamp, commenter_email) ); 

Agregue un poco de datos.

 INSERT INTO publications VALUES (1,'A', 'url 1 goes here'), (2,'A', 'url 2 goes here'), (3,'S', 'url 3 goes here'); INSERT INTO articles VALUES (1,'A', 'A'), (2,'A', 'B'); INSERT INTO stories VALUES (3,'S', 'A'); INSERT INTO comments VALUES (1, now(), 'a@b.com','You''re stupid'), (1, now(), 'b@c.com', 'You''re stupid, too!'); 

Ahora puede crear una vista para mostrar todos los artículos y resolver la unión. Harías lo mismo para cada uno de los subtipos.

 CREATE VIEW articles_all AS SELECT P.*, A.placeholder FROM publications P INNER JOIN articles A ON (A.pub_id = P.pub_id) 

Es posible que prefiera nombres como “published_articles” en lugar de “articles_all”.

Para seleccionar un artículo y todos sus comentarios, puede simplemente juntar las dos tablas. (Pero mira a continuación por qué probablemente no harás eso).

 SELECT A.*, C.* FROM articles_all A LEFT JOIN comments C ON (A.pub_id = C.pub_id) WHERE A.pub_id = 1; 

Probablemente no harías eso para una interfaz web, porque los dbms tendrían que devolver ‘n’ copias del artículo, donde ‘n’ es igual a la cantidad de comentarios. Pero tiene sentido hacerlo en algunas aplicaciones. En aplicaciones donde tiene sentido, usaría una vista actualizable para cada subtipo, y el código de la aplicación usaría las vistas actualizables la mayor parte del tiempo.


La aplicación comercial más común de un supertipo / subtipo involucra a “Partes” (el supertipo), “Organizaciones” y “Individuos” (los subtipos, empresas y personas informales. Las direcciones, como “comentarios” en el ejemplo anterior, están relacionadas con el supertipo, porque todos los subtipos (organizaciones e individuos) tienen direcciones.

Puede usar súper-tipo / subtipo en el diseño de DB para evitar ese problema. Cree un super-tipo para imágenes, video, notas y luego vincule al super-tipo. Mantenga todas las columnas comunes en la tabla de super-tipo.

Aquí hay algunos enlaces a varias preguntas / respuestas similares con modelos:

  • Uno
  • Dos
  • Tres
  • Cuatro

En mi opinión, es mejor que tengas 4 mesas separadas para los comentarios. O podría haber unido tablas. Una tabla para todos los comentarios … por ejemplo: tabla de blog, tabla de comentarios, tabla blog_comment. esto le permitiría tener sus claves foráneas.

 Blog -------- Blog_id {other fields} Blog_Comment -------------- Blog_id Comment_id Comment ------------ Comment_id {other fields}