2012-03-07 57 views
7

Tôi có hai bảng:mối quan hệ One-to-Nhiều trong (Postgre) SQL

bài viết:

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

và các thẻ:

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

posts.tags và tags.tag là cả hai loại văn bản. Những gì tôi muốn là một mối quan hệ từ tags.tag để hàng trong bài viết như vậy mà truy vấn <foo> sẽ cho tôi hàng tương ứng với bài 1 và 2, truy vấn <blah> mang lại cho tôi 2 và 3, <bar> mang lại cho tôi 1 và 3, vv

Tôi đã xem xét các khóa ngoại, nhưng tôi không chắc đó là điều tôi muốn. (và thành thật mà nói, tôi không chắc chắn nó làm gì). Từ những gì tôi có thể nói một khóa ngoại phải bằng một khóa chính/cột duy nhất của một bảng. Nhưng những gì tôi muốn là tất cả các hàng mà posts.tags ~ '.*<foo>.*', vv Tôi cũng muốn để có thể, chẳng hạn, có được tất cả các thẻ bắt đầu bằng b, ví dụ:

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

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

Làm thế nào để có được mối quan hệ tôi đang tìm cho? Có thể không?

EDIT: post_tags

tạo::

Được rồi, những gì tôi đã làm

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

chọn tất cả các bài viết với từ khóa <foo>:

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

Hãy tìm sql ['LIKE'] (http://www.postgresql.org/docs/7.4/static/functions-matching.html). Trong trường hợp của bạn, bạn không thể tạo khóa ngoại, vì giá trị phải khớp với cả hai bảng. –

+4

Thiết kế này rất RẤT. Bạn đang ở trong một môi trường mà bạn có thể thay đổi nó? Một thiết kế phù hợp sẽ là: các bài viết (id, văn bản, các chất liệu); thẻ (id, thẻ); và posts_tags (post_id, tag_id) tham chiếu cả bảng bài đăng và bảng thẻ (mối quan hệ many2many: thẻ có nhiều bài đăng và bài đăng có nhiều thẻ) – Arthur

Trả lời

9

gì bạn thực sự có đang diễn ra ở đây là mối quan hệ nhiều-nhiều. Hãy suy nghĩ về nó: mỗi thẻ có thể có trên một số bài đăng và mỗi bài đăng có thể có nhiều thẻ.

Kiến trúc quan hệ chính xác cho điều này là thêm bảng khác ở giữa như thế này:

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

Sau đó thả các cột tags trên bàn bài viết của mình.

Điều này giải quyết tất cả các vấn đề của bạn, bởi vì bạn có thể nhận tập hợp các thẻ trên bài đăng hoặc tập hợp bài đăng bằng thẻ nhất định bằng cách tham gia chống lại bài đăng theo các hướng khác nhau. Bạn cũng có thể nhận danh sách các thẻ bắt đầu bằng thứ gì đó sử dụng truy vấn LIKE thông thường, điều này sẽ khó khăn hơn nếu bạn có một chuỗi các chuỗi được nối vào một trường.

4

Như Daniel đã đề cập, bạn có mối quan hệ nhiều-nhiều. Chỉ cần làm rõ, đây là cách tất cả 3 bảng sẽ trông với nhiều-nhiều thiết lập:

bài:

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

Tags:

tag 
    --- 
    <foo> 
    <bar> 

Post_Tags bảng vẽ bản đồ:

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

Bài đăng có phải là khóa chính không? Nếu vậy, làm thế nào bạn có thể có bản sao '1' vì các khóa chính là' UNIQUE NOT NULL'? – dman

4

Bình thường hóa mô hình dữ liệu của bạn.Dưới đây là một cách để đại diện cho M: N mối quan hệ mà bạn có:

enter image description here

Xin lưu ý rằng PK POST_TAG là {POST_ID, TAG}, không chỉ {POST_ID}.

Tìm tất cả bài viết được gắn thẻ với 'foo' sẽ trông như thế này:

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

Đối với bài viết được gắn thẻ với một thẻ bắt đầu với 'f', bạn có thể làm điều này:

SELECT * 
FROM POST 
WHERE 
    POST_ID IN (
     SELECT POST_ID 
     FROM POST_TAG 
     WHERE TAG LIKE 'f%' 
    ) 
Các vấn đề liên quan