(Postgresql中的一对多关系)

时间:2012-03-07 18:09:24

标签: sql postgresql

我有两张桌子:

帖子:

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

和标签:

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

posts.tags和tags.tag都是文本类型。我想要的是从tags.tag到帖子中的行的关系,以便查询<foo>会给我与帖子1和2相对应的行,查询<blah>会给我2和3,<bar>给我1和3,等等。

我看过外键,但我不确定这是我想要的。 (老实说,我不确定它的作用)。据我所知,外键必须等于表的主键/唯一列。但我想要的是posts.tags ~ '.*<foo>.*'等所有行。我也希望能够获得以b开头的所有标签,例如:

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

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

我如何获得我正在寻找的关系?有可能吗?

编辑:

好的,我做了什么:

创建post_tags:

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

选择标记为<foo>的所有帖子:

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

3 个答案:

答案 0 :(得分:9)

你实际上发生的事情是多对多的关系。想一想:每个标签可以在几个帖子上,每个帖子可以有几个标签。

正确的关系架构是在中间添加另一个表,如下所示:

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

然后将tags列放在帖子表格上。

这解决了您的所有问题,因为您可以通过在不同方向上与post_tags连接,在帖子或具有给定标签的帖子集上获取标签集。您还可以使用常规LIKE查询获取以某些内容开头的标记列表,如果您在一个字段中连接了一堆字符串,则会更加困难。

答案 1 :(得分:4)

正如丹尼尔所说,你有多对多的关系。只是为了澄清,这里是所有3个表格在多对多设置中的外观:

文章:

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

标签:

    tag
    ---
    <foo>
    <bar>

Post_Tags映射表:

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

答案 2 :(得分:4)

规范化您的数据模型。这是表示你拥有的M:N关系的一种方式:

enter image description here

请注意POST_TAG的PK是{POST_ID,TAG},而不仅仅是{POST_ID}。

查找标有“foo”的所有帖子如下所示:

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

对于标有以“f”开头的标记的帖子,您可以这样做:

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