2012-03-07 66 views
7

yo tenemos dos tablas:Relaciones uno a muchos en (PostgreSQL) SQL

mensajes:

id | ... other stuff ... |  tags       
----+---------------------+-------------- 
    1 |   ...   | <foo><bar> 
    2 |   ...   | <foo><baz><blah> 
    3 |   ...   | <bar><blah><goo> 

y etiquetas:

 tag   
-------------- 
<foo> 
<bar> 
<baz> 
<blah> 
<goo> 

posts.tags y son tags.tag ambos de tipo texto. Lo que quiero es una relación de tags.tag a filas en los puestos de tal manera que la consulta <foo> me daría filas correspondientes a los puestos 1 y 2, la consulta <blah> me da 2 y 3, <bar> me da 1 y 3, etc.

Miré llaves extranjeras, pero no estoy seguro de que sea lo que quiero. (y honestamente, no estoy exactamente seguro de qué es). Por lo que puedo decir, una clave externa debe ser igual a una clave principal/columna única de una tabla. Pero lo que quiero es que todas las filas de tal manera que posts.tags ~ '.*<foo>.*', etc., también quiero ser capaz de, por ejemplo, obtener todas las etiquetas que comienzan con b, por ejemplo:

CREATE VIEW startswithB AS 
SELECT tag 
FROM tags 
WHERE tag ~ '<b.*>'; 

SELECT DISTINCT * FROM posts, startswithB WHERE posts.tags ~ ('.*' || startswithB || '.*'); 

¿Cómo consigo la relación Busco ¿para? ¿Es posible?

EDIT:

bien, lo que he hecho:

crear post_tags:

SELECT posts.id, tags.tag 
INTO post_tags 
FROM posts, tags 
WHERE posts.tags ~ ('.*' || tags.tag || '.*'); 

seleccionar todos los mensajes con la etiqueta <foo>:

SELECT * 
FROM posts 
WHERE posts.id IN (
    SELECT id 
    FROM post_tags 
    WHERE tag = '<foo>' 
); 
+0

Busque el sql ['LIKE'] (http://www.postgresql.org/docs/7.4/static/functions-matching.html). En su caso, no es posible crear una clave externa porque el valor debe coincidir en ambas tablas. –

+4

Este diseño es MUY malo. ¿Estás en un entorno donde puedes cambiarlo? Un diseño apropiado sería: publicaciones (identificación, texto, productos); etiquetas (identificación, etiqueta); y posts_tags (post_id, tag_id) que hace referencia tanto a la tabla de mensajes como a la tabla de etiquetas (relación many2many: una etiqueta tiene muchas publicaciones y una publicación tiene muchas etiquetas) – Arthur

Respuesta

9

Lo que realmente tiene seguir aquí es una relación de muchos a muchos. Piénselo: cada etiqueta puede estar en varias publicaciones, y cada publicación puede tener varias etiquetas.

La arquitectura relacional correcta para esto es agregar otra mesa en el centro de esta manera:

CREATE TABLE post_tags (
    id INTEGER REFERENCES posts, 
    tag VARCHAR REFERENCES tags 
); 

a continuación, colocar la columna de la tags en su tabla de mensajes.

Esto resuelve todos sus problemas, ya que puede obtener el conjunto de etiquetas en una publicación o el conjunto de publicaciones con una etiqueta determinada uniéndose a post_tags en diferentes direcciones. También puede obtener la lista de etiquetas que comienzan con algo utilizando una consulta LIKE regular, que será más difícil si tiene un grupo de cadenas concatenadas en un campo.

4

Como mencionó Daniel, usted tiene una relación de muchos a muchos. Sólo una aclaración, he aquí cómo los 3 mesas mirarían con una configuración de muchos-a-muchos:

Mensajes:

id | ... other stuff ... 
    ---+--------------------- 
    1 | ... 
    2 | ... 

Etiquetas:

tag 
    --- 
    <foo> 
    <bar> 

Post_Tags tabla de correspondencia:

post_id | tag 
    --------+------ 
    1  | <foo> 
    1  | <bar> 
+0

¿Post_id es una clave principal? Si es así, ¿cómo puedes tener duplicado '1' ya que las claves primarias son' UNIQUE NOT NULL'? – dman

4

Normalice su modelo de datos.Aquí es una manera de representar la relación M: N que tiene:

enter image description here

Tenga en cuenta que PK es de POST_TAG {POST_ID, TAG}, no sólo POST_ID {}.

Encontrar todos los mensajes etiquetados con 'foo' se vería así:

SELECT * 
FROM POST 
WHERE 
    POST_ID IN (
     SELECT POST_ID 
     FROM POST_TAG 
     WHERE TAG = 'foo' 
    ) 

Para artículos etiquetados con una etiqueta que comienza con 'f', que podría hacer esto:

SELECT * 
FROM POST 
WHERE 
    POST_ID IN (
     SELECT POST_ID 
     FROM POST_TAG 
     WHERE TAG LIKE 'f%' 
    ) 
Cuestiones relacionadas