我有三个单独的表 - pages
,tags
和pages_tagged
- 包含页面内容,标记名称和分别带有标签ID 的 ID 和页面ID 。
我正在尝试设置MySQL查询,该查询接受搜索项并检查现有标记,找到匹配的标记ID,并返回带有所述标记的所有页面 - 我已经很好地工作了。但是,当我尝试进一步扩展它以查询pages表的title列中的匹配字符串时,事情就变得有点沮丧了。
我的SQL如下:
SELECT tags.id, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
pages.viewcount, pages.sessionId
FROM tags JOIN pages_tagged ON tags.id = pages_tagged.tag_id
JOIN pages ON pages_tagged.page_id = pages.randomId
WHERE (tags.tag = 'ovechkin' OR pages.title LIKE '%ovechkin%')
ORDER BY dateAdded DESC
我知道这里的操作顺序是非常错误的,但是我不能用正确的方法来修改这个查询以使其正常工作。
有人能够指出我明显的错误吗?
修改
为了澄清“肚子”,当查询运行时,它是“成功的”。但是,不会返回任何行。
修改WHERE子句如下以隔离pages.title LIKE'%ovechkin%'永远不会导致返回的行,无论搜索词是什么。
WHERE (pages.title LIKE '%ovechkin%')
编辑2:
以下示例数据。
pages
╔════╦════════════════════════╦═════════════════════╦══════════╦═══════════╗
║ id ║ title ║ dateAdded ║ randomId ║ viewcount ║
╠════╬════════════════════════╬═════════════════════╬══════════╬═══════════╣
║ 57 ║ Ovechkin looping about ║ 2013-04-07 19:26:06 ║ xp3rvju ║ 5 ║
╚════╩════════════════════════╩═════════════════════╩══════════╩═══════════╝
tags
╔════════╦══════════╗
║ id ║ tag ║
╠════════╬══════════╣
║ 25 ║ ovechkin ║
╚════════╩══════════╝
pages_tagged
╔══════════════════╗
║ tag_id | page_id ║
╠══════════════════╣
║ 25 | xp3rvju ║
║ 25 | mpbjbk6 ║
╚══════════════════╝
编辑3:
根据建议,RIGHT JOIN
让pages.title
正常工作。修改后的查询是:
SELECT tags.id, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
pages.viewcount, pages.sessionId
FROM tags RIGHT JOIN pages_tagged ON tags.id = pages_tagged.tag_id
RIGHT JOIN pages ON pages_tagged.page_id = pages.randomId
WHERE (tags.tag = 'ovechkin' OR pages.title LIKE '%ovechkin%')
ORDER BY dateAdded DESC
剩下的问题是,如果某个网页的标题和相关标签中的搜索字词相同,则会返回两次。我已经尝试修改它以在select上包含DISTINCT
,如下所示,但这对返回的行没有影响。
SELECT DISTINCT tags.id, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
编辑4:
也可以包括防止重复的最终解决方案 - GROUP BY
。
SELECT tags.id, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
pages.viewcount, pages.sessionId
FROM pages
LEFT JOIN pages_tagged ON pages.randomId = pages_tagged.page_id
LEFT JOIN tags ON tags.id = pages_tagged.tag_id
WHERE (tags.tag = 'ovechkin' OR pages.title LIKE '%ovechkin%')
GROUP BY pages.randomId
ORDER BY dateAdded DESC
答案 0 :(得分:0)
请尝试以下操作:
select * from
(SELECT tags.id as tid, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
pages.viewcount, pages.sessionId
FROM tags JOIN pages_tagged ON tags.id = pages_tagged.tag_id
JOIN pages ON pages_tagged.page_id = pages.randomId
WHERE tags.tag = 'thang'
union
( SELECT tags.id as tid, pages_tagged.page_id, pages.id, pages.randomId, pages.title,
DATE_FORMAT( pages.dateAdded, '%M %e, %Y' ) AS dateAdded,
pages.viewcount, pages.sessionId
FROM pages JOIN pages_tagged on pages_tagged.page_id = pages.randomId
JOIN tags ON tags.id = pages_tagged.tag_id
WHERE pages.title LIKE '%thang%'
)
) as a
ORDER BY a.dateAdded DESC
这样,它会在“正确”页面之后选择第一个“正确”的标签。
答案 1 :(得分:0)
了解联接的工作原理非常重要,这里有一个简单的解释:http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
由于您正在寻找标题中的OR
标记,我猜您希望使用RIGHT JOIN
作为关系,因为此查询不会返回任何页面没有标记。
目前,如果您的网页标题为ovechkin
但没有标记,则您无法使用此查询找到它。
这就是我尝试过的:http://sqlfiddle.com/#!2/c25c5/2
通常,构建查询的方式意味着您获取所有标记,然后加入任何标记的页面。没有WHERE
子句的行为如下:
执行普通JOIN
只会返回标记页面,如果数据库中没有标记,则不会获得单行。
使用LEFT JOIN
表示即使没有标记任何页面,您也会获得每个标记的结果。
使用RIGHT JOIN
表示即使没有标记,也没有标记任何页面,您将获得所有页面的所有结果行。
对于所有这些,任何没有数据的字段都将填充为null。
我建议将查询更改为此(删除某些字段以提高可读性):
SELECT tags.id, pages_tagged.page_id, pages.id, pages.randomId
FROM pages
LEFT JOIN pages_tagged ON pages.randomId = pages_tagged.page_id
LEFT JOIN tags ON tags.id = pages_tagged.tag_id
WHERE (tags.tag = 'ovechkin' OR pages.title LIKE '%ovechkin%')
如果它有多个标记,您将多次获得同一页面。