【问题标题】:MySQL: How to SELECT only three of each differing x-column-nameMySQL:如何只选择每个不同的 x-column-name 中的三个
【发布时间】:2019-09-29 03:13:30
【问题描述】:

我想以一种面向未来的方式展示我的博客。所以我需要做一个查询,如果它们被创建,它们将引用新的博客类型。因此,x-column-name。在这种情况下,就是 blogType。此选择查询应包含所有博客类型的博客信息,但为每个博客类型获取 3 个博客。这有点令人困惑,所以这就是我重申的原因!

我已经在谷歌搜索如何限制结果方面做了一些工作。如下图:

 $query = 'SELECT * FROM blogs
              ORDER BY dateWritten
              ASC LIMIT 3';

我将使用数组和 foreach 循环将结果输出到 blog_rss.php。我从这样的函数中获取数组:

function get_Recent_Blogs() {
    global $db;
    $query = 'SELECT * FROM blogs
              ORDER BY dateWritten
              ASC LIMIT 3';
    try {
        $statement = $db->prepare($query);
        $statement->execute();
        $result = $statement->fetchAll(PDO::FETCH_ASSOC);
        $statement->closeCursor();
        return $result;
    } catch (PDOException $e) {
        $error_message = $e->getMessage();
        display_db_error($error_message);
    }
}

这不是太重要,但至少它给你一些背景。

    SELECT *
    FROM (
         SELECT b.*, ROW_NUMBER() OVER (PARTITION BY b.blogType ORDER BY b.blogID DESC) as rn
         FROM blogs b
         ) x
    WHERE x.rn <= 3
    ORDER BY x.blogType, x.blogID DESC';

所以我已尽力实施该解决方案,但我遇到了一些错误。我不确定我是否应该为此开始新帖子,但上面的代码是我使用的,这是我得到的错误:

You have an error in your SQL syntax; it seems the error is around: '( PARTITION BY b.blogType ORDER BY b.dateWritten DESC ' at line 7

【问题讨论】:

  • 你的 MySQL 版本是多少?
  • 8.0.13 是我的版本
  • 所以让我们澄清一下:您需要一个查询来返回每种博客类型的三篇最新文章。对吗?
  • 完全正确。是的!

标签: php mysql limit-per-group


【解决方案1】:

由于您的 MySQL 版本支持窗口函数,因此您可以使用 ROW_NUMBER(),它将按博客类型枚举您的条目。然后你只需要选择每种类型的前三行。

SELECT *
FROM (
    SELECT b.*, ROW_NUMBER() OVER (PARTITION BY b.type ORDER BY b.dateWritten DESC) as rn
    FROM blogs b
) x
WHERE x.rn <= 3
ORDER BY x.type, x.dateWritten DESC -- adjust as needed

注意事项:

  • 我假设博客类型由type 列决定。根据需要进行调整。
  • 您应该使用DESC 而不是ASC,因为您想获取最新的条目。
  • 我宁愿使用 AUTO_INCEMENT id 列而不是 dateWritten 进行排序。这更可靠,因为 DATE 甚至 TIMESTAMP 都可以有重复项。

对于不支持窗口函数的旧版本,我会首先获取所有类型并生成一个 UNION ALL 查询。对于 PDO,它可能类似于以下内容:

$types = $db
       ->query('SELECT DISTINCT type from blogs ORDER BY type')
       ->fetchAll(PDO::FETCH_COLUMN);

$subqueries = array_map(function($type){
    return '(SELECT * FROM blogs WHERE type = ? ORDER by dateWritten DESC LIMIT 3)';
}, $types);

$query = implode(' UNION ALL ', $subqueries) . ' ORDER BY type, dateWritten DESC';

$statement = $db->prepare($query);
$statement->execute($types);
$result = $statement->fetchAll(PDO::FETCH_ASSOC);

这将生成以下查询:

(SELECT * FROM blogs WHERE type = ? ORDER by dateWritten DESC LIMIT 3)
UNION ALL
...
UNION ALL
(SELECT * FROM blogs WHERE type = ? ORDER by dateWritten DESC LIMIT 3)
ORDER BY type, dateWritten DESC

注意 1:即使执行了两个查询,给定 (type, dateWritten) 上的复合索引,这仍然比其他解决方案更快。当您有几种博客类型并且每种类型有很多文章时,这甚至可以比 ROW_NUMBER() 解决方案更快。

注意 2:我通常会有一个单独的类型表,blogs 表将引用主键 type_id 列。在这种情况下,第一个查询将是 SELECT type_id from blog_types,子查询将具有条件 WHERE type_id = ?

【讨论】:

  • 谢谢!我是 MySQL 的新手,所以这很有帮助。我很感激!
  • 你不会碰巧知道这里的语法有什么问题吗?
  • @DanielJ.Dunevant 你有错误吗?它在这里对我有用:db-fiddle.com/f/s3qAyCDo7ScQorPg98sCMt/0
  • 我做到了... :( 在测试 5.7 中有效的代码时,我得到了以下错误:“SQLSTATE[HY093]: Invalid parameter number: no parameters were bound。”小提琴代码是不过对于 8.0,所以它目前对我不起作用。
  • @DanielJ.Dunevant 你写的版本是 8.0.13,但是“near ( PARTITION”) 的错误告诉我不是。但是 - 这就是我写第二个解决方案的原因。“不参数被绑定“ - 似乎你已经改变了一些东西。确保你在这里传递类型:$statement-&gt;execute($types);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
相关资源
最近更新 更多