根据带有同义行

时间:2015-06-28 16:00:18

标签: mysql sql subquery tagging

我有三个表:文章,标签和articles_tags(交汇点)。

tags内我有3个(相关)列: idnamealiasalias列包含早期同义标记的ID(如果存在)(否则为NULL)。 没有循环或链:所有同义标记都包含相同的别名。例如:

tags

id    |    name    |    alias
------------------------------------
------------------------------------
8     |   pencil   |    NULL
------------------------------------
------------------------------------
3072  |   pencils  |      8
------------------------------------
------------------------------------
3073  | blue pencil|      8
------------------------------------

(标签必须具有此功能,因为它们是用户输入的。)

现在,我们想要搜索包含标记pencilscats的所有文章。我希望他们包含所有其他同义标签(铅笔蓝色铅笔 tomcat 小猫等。)。

我提出的查询如下:

SELECT * FROM `articles` WHERE id IN
    (SELECT article_id FROM `articles_tags` WHERE id IN
         (SELECT id FROM `tags` WHERE COALESCE(alias, id) IN
            (SELECT id FROM `tags` WHERE name IN
                ("pencils", "cats")
        )
    )
)

我相信它有效,但我认为使用 IN 的4个子查询可能有更好的方法(性能是关键,因为这将是常见的搜索)。

我非常感谢为更好的解决方案提供指导。

感谢。

奖金问题

如果我需要查找不包含其他标签的文章,那该怎么办?

即,选择所有仅包含标签的文章" cats"和#34;狗"将返回唯一标签为("猫"),("狗")或("猫","狗")的文章

编辑:表格结构:

id    |    name    |    alias
------------------------------------
...
------------------------------------
8     |   pencil   |    NULL
------------------------------------
...
------------------------------------
3072  |   pencils  |      8 (pencil)
------------------------------------
------------------------------------
3073  | blue pencil|      8 (pencil)
------------------------------------
------------------------------------
6088  |    cats    |     NULL
------------------------------------
------------------------------------
7098  |    dogs    |     NULL
------------------------------------
------------------------------------
7099  |  kittens   |     6088 (cats)
------------------------------------
------------------------------------
7102  |  chiwawa   |     7098 (dogs)
------------------------------------

制品

id    |        title       |    content
----------------------------------------
...
----------------------------------------
1     |   I love writing   |    ...
----------------------------------------
...
----------------------------------------
42    |Tips for pet owners |    ...
----------------------------------------
----------------------------------------
108   |  Drawing my dog    |    ...
----------------------------------------

articles_tags

id    |      article_id      |    tag_id
------------------------------------
...
------------------------------------
19    |   1(I love writing)  |    3072 (pencils)
------------------------------------
------------------------------------
21    |   1(I love writing)  |    3010 (poetry)
------------------------------------
------------------------------------
22    |   1(I love writing)  |    123  (books)
------------------------------------
------------------------------------
34    | 42(Tips for pet ...) |    6088 (cats)
------------------------------------
------------------------------------
35    | 42(Tips for pet ...) |    7098 (dogs)
------------------------------------
...
------------------------------------
78    | 108(Drawing my dog) |     7098 (dogs)
------------------------------------
------------------------------------
78    | 108(Drawing my dog) |     8    (pencil)
------------------------------------

所需的输出:

正在搜索chiwawacats会产生"宠物主人提示","吸引我的狗"。 搜索pencildogs应该会产生"我喜欢写作","画我的狗"。

对于第二个(奖金)部分: 搜索chiwawakittens应该会产生"宠物主人提示"和"绘制我的狗"因为它还有一个pencils标记。

抱歉文字数量。

2 个答案:

答案 0 :(得分:1)

您可以通过以下方式获取文章ID:

select ata.article_id
from articles_tags ata join
     tags t
     on ata.tag_id = t.id
where t.name in ('pencil', 'cats')
group by ata.article_id
having count(distinct t.name) = 2;

对于第二个问题,您可以使用条件聚合。这是一种方法:

select ata.article_id
from articles_tags ata join
     tags t
     on ata.tag_id = t.id
where t.name in ('pencil', 'cats')
group by ata.article_id
having sum(t.name = 'pencil') > 0 and sum(t.name = 'cats') > 0;

如果您需要,可以加入articles以获取其他列。

答案 1 :(得分:1)

你在这里基本上有两个问题......第一个是关系部门 - 选择适用于父记录的标签,这本身可能会有点乐趣。以下是两个相关链接:

https://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/(Celko)

这个问题的答案提供了大约十几种不同的查询方式(以及使用PostgreSQL的性能基准)。信息量很大:

How to filter SQL results in a has-many-through relation

至于#34;铅笔与铅笔"类型标签,我建议通过输入应用程序处理这个。创建一个"过滤器"将标签映射到其他固有标签的种类。所以,当有人输入"铅笔"标签,它自动a)过滤到"铅笔",或b)输入铅笔和铅笔。这对像"蓝色铅笔"这样的东西特别有用。鉴于如上所述的关系划分问题的相对复杂性,我认为如果"蓝色铅笔"那么你会发现自己更容易管理数据模型。添加了"铅笔"和"蓝色铅笔" (也许" blue")标记到数据库中。

在某一点上,逻辑应成为应用程序域的一部分并远离数据库。我相信这是一个很好的例子。否则,你可能会冒险尝试将数据库引擎强制转换为它真正没有设计的东西,这根本就没什么乐趣。