Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何在3个表之间约束标记_Mysql_Tags_Constraints - Fatal编程技术网

Mysql 如何在3个表之间约束标记

Mysql 如何在3个表之间约束标记,mysql,tags,constraints,Mysql,Tags,Constraints,我正在开发一个标签系统,它应该做的是你可以有一个查询和选择的标签,例如jquery和javascript,库的标签。它应该只显示与查询相关的脚本,并且只显示具有标记的脚本。这是数据库布局: 脚本表: +-----------+---------------+ | script_id | name | +-----------+---------------+ | 1 | jQuery | | 2 | Sencha Touch |

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

脚本表:

+-----------+---------------+
| 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
,但它不应该选择,因为它不包含
library
标记,而
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 |
+-----------+---------------+
如果我将
更改为
,它将不会返回任何内容,或者如果我从标记
中删除括号,它也不会返回任何内容

如何使查询约束标记?

我的尝试:

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
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
这有点像黑客,它首先查找与任何标记匹配的所有条目,然后按名称分组,只返回那些匹配数等于提供的标记数的条目:)


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

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

在将它们分组之前,将生成三个单独的行:

+-----------+-----------+---------------+
|     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
尝试一下:

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
子句中
in的元素数量


以下是。

您是否尝试了
内部联接
而不是
左侧外部联接
?但并非所有脚本都已标记。结果看起来正常。您要求脚本匹配“jQuery”和“javascript”或“library”的标记url。这就是结果。顺便说一句,不需要使用与表名相同的别名来为表别名(“从脚本中选择[…]);您可以省略别名。如果要缩短表名或多次引用同一表,您只需要的别名。请查看以下标记解决方案: