2012-03-07 15 views
7

Mam dwie tabele:jeden-do-wielu relacji w (Postgre) SQL

posty:

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

i tagi:

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

posts.tags i tags.tag są oba teksty typu. Co chcę to relacja z tags.tag do rzędach na stanowiskach takich zapytań <foo> że da mi wiersze odpowiadające Posty 1 i 2, zapytań <blah> daje mi 2 i 3 <bar> daje mi 1 i 3, itd

Sprawdziłem klucze obce, ale nie jestem pewien, czy tego chcę. (i szczerze mówiąc, nie jestem do końca pewien, co robi). Z tego, co mogę powiedzieć, klucz obcy musi być równy kluczowi podstawowemu/unikalnej kolumnie tabeli. Ale to, co chcę jest taka, że ​​wszystkie wiersze posts.tags ~ '.*<foo>.*', itd. Chcę również być w stanie, powiedzmy, uzyskać wszystkie znaczniki, które rozpoczynają się od B, np

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

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

Jak uzyskać relację szukam dla? Czy to możliwe?

EDIT:

Dobra, co zrobiłem:

tworzą post_tags:

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

zaznaczyć wszystkie posty z tagiem <foo>:

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

Poszukaj sql ["LIKE"] (http://www.postgresql.org/docs/7.4/static/functions-matching.html). W twoim przypadku nie można utworzyć klucza obcego, ponieważ wartość musi być zgodna w obu tabelach. –

+4

Ten projekt jest BARDZO zły. Czy jesteś w środowisku, w którym możesz to zmienić? Odpowiednim projektem będzie: posty (identyfikator, tekst, materiały); tagi (identyfikator, tag); i posts_tags (post_id, tag_id), które odwołują się zarówno do tabeli postów, jak i tabeli znaczników (many2many relacji: znacznik ma wiele postów, a post ma wiele tagów) – Arthur

Odpowiedz

9

Co trzeba rzeczywiście dzieje się tu relacja wiele do wielu. Pomyśl o tym: każdy tag może znajdować się w kilku postach, a każdy post może mieć kilka tagów.

Prawidłowe architektura relacyjnej dla tego celu jest dodanie innej tabeli w środku tak:

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

Następnie upuść kolumnę tags na stole posty.

Rozwiązuje to wszystkie problemy, ponieważ możesz uzyskać zestaw tagów na stanowisku lub zestawie postów z danym znacznikiem, łącząc się z post_tags w różnych kierunkach. Możesz również uzyskać listę znaczników, które zaczynają się od czegoś za pomocą zwykłego zapytania LIKE, co będzie trudniejsze, jeśli masz kilka ciągów połączonych w jednym polu.

4

Jak wspomniał Daniel, masz związek wiele do wielu. Tylko dla wyjaśnienia, oto jak wszystkie 3 stoły wyglądałaby o wiele-do-wielu Setup:

Wypowiedzi:

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

Tagi:

tag 
    --- 
    <foo> 
    <bar> 

Post_Tags tabela mapowania:

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

Czy post_id jest kluczem podstawowym? Jeśli tak, jak możesz mieć duplikat '1', ponieważ klucze podstawowe to' UNIQUE NOT NULL'? – dman

4

Normalizuj swój model danych.Oto jeden ze sposobów reprezentowania M: N relacji, że masz:

enter image description here

Zwróć uwagę, że PK POST_TAG jest {POST_ID, etykietka}, a nie tylko {POST_ID}.

Znalezienie wszystkie posty oznaczone tagiem „foo” będzie wyglądać następująco:

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

postów oznaczonych tagiem, który rozpoczyna się od „f”, można to zrobić:

SELECT * 
FROM POST 
WHERE 
    POST_ID IN (
     SELECT POST_ID 
     FROM POST_TAG 
     WHERE TAG LIKE 'f%' 
    ) 
Powiązane problemy