绊倒加入并从单独的表中选择

时间:2013-04-08 15:08:47

标签: mysql sql join

我有三个单独的表 - pagestagspages_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 JOINpages.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    

2 个答案:

答案 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%')

如果它有多个标记,您将多次获得同一页面。