2011-09-14 72 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