如何在查找最常用记录的查询中添加例外?

时间:2015-05-09 14:43:38

标签: mysql sql

我正在建立一个网站,用户可以在其中提交截屏视频并与之关联。

以下是构成数据库的3个表:

Screencasts:

| screencastId | title                                            |
|--------------|--------------------------------------------------|
| CF9S4QZuV30  | Go Programming                                   |
| ef-6NZjBtW0  | How to Make Android Apps                         |
| F3WpBsc0QEw  | Git & GitHub: Creating a Repository (2/11)       |
| Ggh_y-33Eso  | Learn HTML in 15 Minutes                         |
| GrycH6F-ksY  | jQuery Tutorials: Submitting a Form with AJAX    |
| N4mEzFDjqtA  | Python Programming                               |
| QRmmISj6Rrw  | Learn PHP: Your first file                       |
| WPvGqX-TXP0  | Java Programming                                 |
| wz3kElLbEHE  | SASS Tutorial                                    |
| Xx-XZwJT76w  | Setting Up A Development Environment With Bowery |

Tags:

| tagName |
|---------|
| Android |
| Bowery  |
| Git     |
| Go      |
| Html    |
| Java    |
| jQuery  |
| PHP     |
| Python  |
| Sass    |


ScreencastTags

| screencastId | tagName |
|--------------|---------|
| CF9S4QZuV30  | Go      |
| ef-6NZjBtW0  | Android |
| ef-6NZjBtW0  | Java    |
| F3WpBsc0QEw  | Git     |
| Ggh_y-33Eso  | Html    |
| GrycH6F-ksY  | jQuery  |
| N4mEzFDjqtA  | Python  |
| QRmmISj6Rrw  | PHP     |
| WPvGqX-TXP0  | Java    |
| wz3kElLbEHE  | Sass    |
| Xx-XZwJT76w  | Bowery  |

该网站允许用户查看 9 最受欢迎的代码:

enter image description here

我用来确定这9个最受欢迎的标签的查询如下:

SELECT t.tagName
FROM tags t
JOIN screencastTags m
    ON m.tagName = t.tagName
GROUP BY t.tagName
ORDER BY COUNT(*) DESC, t.tagName DESC
LIMIT 9

如您所见,有一个名为其他第10个菜单项。点击后,系统会向用户显示其中9个最受欢迎的标签的截屏视频。

我用来确定这些截屏的查询如下:

SELECT
    v.screencastId,
    v.title,
    GROUP_CONCAT(m.tagName) as tags
FROM screencasts v
JOIN screencastTags m
    ON v.screencastId = m.screencastId
WHERE m.tagName NOT IN (
    SELECT * FROM (
        SELECT t.tagName
        FROM tags t
        JOIN screencastTags m
            ON m.tagName = t.tagName
        GROUP BY t.tagName
        ORDER BY COUNT(*) DESC, t.tagName DESC
        LIMIT 9) as t)
GROUP BY v.screencastId
ORDER BY v.ReferralCount DESC

不幸的是,这个查询确实表现得像我希望的那样。结果如下表所示:

| screencastId | title                    | tagName |
|--------------|--------------------------|---------|
| ef-6NZjBtW0  | How to Make Android Apps | Android |

我希望它返回此表:

| screencastId | title                    | tagName       |
|--------------|--------------------------|---------------|
| ef-6NZjBtW0  | How to Make Android Apps | Android, Java |

在这种情况下如何达到预期效果?

如您所见,子查询返回9个最受欢迎的标签,其中包括标签 Java 。由于查询返回子查询结果中标记为的截屏视频,因此不包括标记 Java 。它应该是,因为截屏视频被标记为 Android Java Android 不是9个最受欢迎的代码之一, Java 是。

1 个答案:

答案 0 :(得分:1)

如果你想要没有9个标签的屏幕转换,那么逻辑更像是这样:

SELECT v.screencastId, v.title,
       GROUP_CONCAT(m.tagName) as tags
FROM screencasts v JOIN
     screencastTags m
     ON v.screencastId = m.screencastId LEFT JOIN
     (SELECT t.tagName
      FROM tags t JOIN
           screencastTags m
           ON m.tagName = t.tagName
      GROUP BY t.tagName
      ORDER BY COUNT(*) DESC, t.tagName DESC
      LIMIT 9
     ) tags9
     ON m.tagname = tags9.tagname
GROUP BY v.screencastId, v.title
HAVING SUM(tags9.tagname IS NOT NULL) = 0;

这是做什么的? LEFT JOIN是与九个原始标记匹配的标记(假设数据库尚未在两个查询之间更新)。聚合是由屏幕情况决定的。然后HAVING子句检查九个标签是否匹配。这可以保证九个标记中没有一个是此查询返回的值。

编辑:

哎呀,我想我误解了这个问题。我以为你想要没有九个标签的屏幕转换。相反,您希望屏幕转换的所有标签都有其他标签。

这实际上是上述查询的一个小变化。而不是检查所有标记是否不同,这将检查任何标记是否不同。唯一的变化是HAVING子句:

SELECT v.screencastId, v.title,
       GROUP_CONCAT(m.tagName) as tags
FROM screencasts v JOIN
     screencastTags m
     ON v.screencastId = m.screencastId LEFT JOIN
     (SELECT t.tagName
      FROM tags t JOIN
           screencastTags m
           ON m.tagName = t.tagName
      GROUP BY t.tagName
      ORDER BY COUNT(*) DESC, t.tagName DESC
      LIMIT 9
     ) tags9
     ON m.tagname = tags9.tagname
GROUP BY v.screencastId, v.title
HAVING SUM(tags9.tagname IS NULL) > 0;