2011-09-14 110 views
0

我目前正在編寫標籤雲系統。多對多SQL選擇

所以我寫了下面的SQL架構:

CREATE TABLE bookmark_model_bookmark (
    id INTEGER NOT NULL, 
    link VARCHAR(255), 
    title VARCHAR(140), 
    description TEXT, 
    PRIMARY KEY (id) 
); 

CREATE TABLE bookmark_model_tag (
    id INTEGER NOT NULL, 
    name VARCHAR(20), 
    PRIMARY KEY (id) 
); 

CREATE TABLE bookmark_tag (
    bookmark_model_bookmark_id INTEGER NOT NULL, 
    bookmark_model_tag_id INTEGER NOT NULL, 
    PRIMARY KEY (bookmark_model_bookmark_id, bookmark_model_tag_id), 
    CONSTRAINT bookmark_model_bookmark_tags_fk FOREIGN KEY(bookmark_model_bookmark_id) REFERENCES bookmark_model_bookmark (id), 
    CONSTRAINT bookmark_model_tag_bookmarks_fk FOREIGN KEY(bookmark_model_tag_id) REFERENCES bookmark_model_tag (id) 
); 

而且隨着數據量小的填充:

SELECT * FROM bookmark_model_bookmark; 

1|http://braindead.fr|braindead| 
2|http://example.fr|example|example text 

SELECT * FROM bookmark_model_tag; 

1|test 
2|braindead 
3|example 

SELECT * FROM bookmark_tag; 

1|1 
1|2 
2|1 
2|3 

在更具可讀性方面:

  • 書籤#1名爲braindead參考http://braindead.fr/並有兩個標籤:「test」和「braindead」。
  • 書籤#2命名示例參考http://example.fr/並且必須標記「test」和「example」。

因此,我開發的下一步是選擇鏈接到書籤的所有標籤,這些書籤用選定標籤列表標記。

例如,我傳入參數「測試」它必須返回「braindead」和「示例」,因爲兩者都標有測試標籤。

但是,如果我傳入參數「test」和「braindead」,則只有「braindead」必須由查詢返回,因爲它是唯一標記了「test」和「braindead」的書籤。

SELECT * 
FROM bookmark_model_tag AS tag 
INNER JOIN bookmark_tag ON (bookmark_tag.bookmark_model_tag_id = tag.id) 
WHERE bookmark_tag.bookmark_model_bookmark_id IN (/* Here my subquery */); 

但我無法設法找出子查詢。我有這樣的開始:

SELECT bookmark.id 
FROM bookmark_model_bookmark AS bookmark 
INNER JOIN bookmark_tag ON (bookmark.id = bookmark_tag.bookmark_model_bookmark_id) 
WHERE /* what to write here ? */ 

只是要準確,我的查詢的輸入參數是標籤ID的數組。

所以在這裏我卡住了。

編輯

我使用的ORM(SQLAlchemy的),用於建立自己的查詢,這是建立查詢,看起來像這樣:

SELECT tag.id AS tag_id, tag.name AS tag_name, count(tag.id) AS count_1 
FROM tag, bookmark_tag, (
    SELECT bookmark.id AS id 
    FROM bookmark, bookmark_tag 
    WHERE bookmark.id = bookmark_tag.bookmark_id 
    AND bookmark_tag.tag_id IN (1, 2) 
    GROUP BY bookmark.id 
    HAVING count(bookmark.id) = 2) AS anon_1 
WHERE tag.id = bookmark_tag.tag_id 
AND bookmark_tag.bookmark_id = anon_1.id 
AND tag.id NOT IN (1, 2) 
GROUP BY tag.id 
+3

這是[Relational Division](http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/)。最常用的方法似乎是'GROUP BY'和'COUNT' –

+0

我的Where子句現在是「WHERE bookmark_tag.bookmark_model_tag_id IN($ TAG_LIST_ID)GROUP BY bookmark.id HAVING count(*)== $ TAG_LIST_SIZE」。這是你所期望的嗎? –

+0

是的。假設'bookmark_tag'有一個唯一的約束,所以你不能有相同組合的重複。 –

回答

0

不知道這仍然是一個問題,但查詢應該是這個樣子:

DECLARE @array TABLE(
    tag varchar(50) 
) 
INSERT INTO @array 
VALUES('test') 
INSERT INTO @array 
VALUES('braindead') 

select * from bookmark_model_bookmark 
where id in(
    select bookmark_model_bookmark_id FROM bookmark_tag x INNER JOIN bookmark_model_tag t ON t.id = x.bookmark_model_tag_id 
    where t.name in (select tag from @array) 
    group by bookmark_model_bookmark_id 
    having bookmark_model_bookmark_id >= (select count(0) from @array)) 

在上面的例子中我用了一個表,但在運行任何形式的分裂上一個逗號分隔字符串輸入將以類似的位置結束。讓我知道,如果這是你正在尋找或如果我得到了錯誤的結束?謝謝,

+0

它實際上是一種解決方案。我用我目前的解決方案更新了我的問題。 –

+0

好了,關閉這個問題是個好主意。防止像我這樣的人浪費寶貴的時間? – Christo