3

我正在开发一个标签系统,它应该做的是你可以有一个查询和选定的标签,例如,jquery的标签。它应该只显示与查询相关的脚本并且只显示具有标签的脚本。这是数据库布局:javascriptlibrary

脚本表:

+-----------+---------------+
| script_id | name          |
+-----------+---------------+
|         1 | jQuery        |
|         2 | Sencha Touch  |
|         3 | Codeigniter   |
|         4 | Google Chrome |
|         5 | memcached     |
|         6 | PHP           |
|         7 | MooTools      |
|         8 | node.js       |
|         9 | jQuery Mobile |
+-----------+---------------+

标签表:

+--------+-------------+-------------+
| tag_id | name        | url_name    |
+--------+-------------+-------------+
|      1 | JavaScript  | javascript  |
|      2 | Library     | library     |
|      3 | PHP         | php         |
|      4 | MySQL       | mysql       |
|      5 | Cache       | cache       |
|      6 | HTML        | html        |
|      7 | Open source | open-source |
+--------+-------------+-------------+

标记表:

+-----------+--------+-----------+
| tagged_id | tag_id | script_id |
+-----------+--------+-----------+
|         1 |      1 |         1 |  # javascript -- jQuery
|         2 |      2 |         1 |  # library    -- jQuery
|         3 |      1 |         9 |  # javascript -- jQuery mobile
+-----------+--------+-----------+

当我运行我的 SQL 时,它仍然会启动,jQuery Mobile但它不应该,因为它不包含librarywhere dos 的标签jQuery,我需要它来约束必须满足所选标签的结果。

这是我的 SQL:

SELECT scripts.script_id,
       scripts.name
FROM
(
    scripts scripts

    LEFT OUTER JOIN tagged tagged ON tagged.script_id = scripts.script_id

    LEFT OUTER JOIN tags tags ON tags.tag_id = tagged.tag_id
)
WHERE MATCH(scripts.name) AGAINST ('jquery*' IN BOOLEAN MODE) AND ( tags.url_name = 'javascript' OR tags.url_name = 'library' )
GROUP BY script_id
ORDER BY scripts.name
LIMIT 0, 25

它返回:

+-----------+---------------+
| script_id | name          |
+-----------+---------------+
|         1 | jQuery        |
|         9 | jQuery Mobile |
+-----------+---------------+

如果我更改ORAND,它根本不会返回任何东西,或者如果我从标签(和中删除括号),它也不会返回任何东西。

如何使查询约束标签?

4

4 回答 4

2

试试这个:

select s.script_id, s.name from scripts s
join tagged tj on s.script_id = tj.script_id
join tags t on t.tag_id = tj.tag_id
where s.name like 'jQuery%' and t.url_name in ('javascript', 'library')
group by s.script_id, s.name
having count(*) = 2
order by s.name
limit 25

唯一需要考虑的是,2必须用in子句中的元素数量替换。

这是小提琴

于 2012-04-25T23:54:42.587 回答
1

您的解决方案的主要问题是它在连接在一起时会创建多行,但每一行只有一个标签值。如果您使用 OR 条件,则任何匹配的标签都足以返回。使用 AND 没有行可以有两个不同的值。

在将它们组合在一起之前,会生成三个单独的行:

+-----------+-----------+---------------+
|     tag_id| script_id | name          |
+-----------+-----------+---------------+
|         1 |         1 | jQuery        |
|         2 |         1 | jQuery        |
|         1 |         9 | jQuery Mobile |
+-----------+-----------+---------------+

要解决这个问题,您必须使用 OR 条件,但在组之后,使用

HAVING count(tag_id) = 2

这告诉 sql,根据他们有多少标签来评估每个组,并只留下那些正好有 2 个标签的组。

因此,基于您的代码的解决方案:

SELECT scripts.script_id,
       scripts.name
FROM
(
    scripts scripts

    LEFT OUTER JOIN tagged tagged ON tagged.script_id = scripts.script_id

    LEFT OUTER JOIN tags tags ON tags.tag_id = tagged.tag_id
)
WHERE MATCH(scripts.name) AGAINST ('jquery*' IN BOOLEAN MODE) AND ( tags.url_name = 'javascript' OR tags.url_name = 'library' )
GROUP BY script_id
HAVING count(tag_id) = 2
ORDER BY scripts.name
LIMIT 0, 25
于 2012-04-24T09:18:09.037 回答
0

我的尝试:

SELECT s.script_id, s.name, so_tags.url_name 
  FROM so_scripts s 
       LEFT JOIN so_tagged USING (script_id) 
       LEFT JOIN so_tags USING (tag_id)
  WHERE s.script_id IN 
  (
    SELECT td.script_id FROM so_tagged td 
      LEFT JOIN so_tags t USING (tag_id) 
    WHERE t.url_name = "javascript" OR t.url_name = "library"
  ) 
GROUP BY url_name HAVING COUNT(s.name) = 2

这有点像 hack,它首先查找与任何标签匹配的所有条目,然后按名称分组并仅返回那些匹配数量等于提供的标签数量的条目:)

不确定 3、4 或更多标签的速度有多快,但至少它可以工作:)

于 2012-04-19T18:53:13.500 回答
0
SELECT s.script_id,
       s.name
FROM
        scripts AS s
    INNER JOIN 
        tagged AS st1
      ON  st1.script_id = s.script_id
    INNER JOIN tags AS tag1
      ON  tag1.tag_id = st1.tag_id
      AND tag1.url_name = 'javascript'
    INNER JOIN 
        tagged AS st2
      ON  st2.script_id = s.script_id
    INNER JOIN tags AS tag2
      ON  tag2.tag_id = st2.tag_id
      AND tag2.url_name = 'library'
ORDER BY s.name
LIMIT 0, 25
于 2012-04-19T18:43:50.670 回答