Отношения один-ко-многим в (Postgre) SQL - PullRequest
7 голосов
/ 07 марта 2012

У меня есть две таблицы:

posts:

 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 оба имеют тип text.То, что я хочу, это отношение от 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 ]

9 голосов
/ 07 марта 2012

То, что у вас на самом деле происходит, это отношения многие ко многим. Подумайте об этом: каждый тег может быть в нескольких сообщениях, и каждый пост может иметь несколько тегов.

Правильная реляционная архитектура для этого заключается в добавлении еще одной таблицы посередине, например:

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

Затем опустите столбец tags в таблице сообщений.

Это решает все ваши проблемы, потому что вы можете получить набор тегов для сообщения или набор сообщений с данным тегом, объединившись с post_tags в разных направлениях. Вы также можете получить список тегов, которые начинаются с чего-то, используя обычный запрос LIKE, который будет более сложным, если в одном поле объединено несколько строк.

4 голосов
/ 07 марта 2012

Нормализуйте вашу модель данных. Вот один из способов представить ваши отношения M: N:

enter image description here

Обратите внимание, что PK POST_TAG - это {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%'
    )
4 голосов
/ 07 марта 2012

Как упоминал Даниил, у вас есть отношения многие ко многим. Просто для пояснения, вот как все 3 таблицы будут выглядеть при установке «многие ко многим»:

Сообщения:

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

Теги:

    tag
    ---
    <foo>
    <bar>

Таблица сопоставления Post_Tags:

    post_id | tag
    --------+------
    1       | <foo>
    1       | <bar>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...