【问题标题】:MySQL: How to get n latest rows of a distinct typeMySQL:如何获取不同类型的最后 n 行
【发布时间】:2009-06-04 13:34:16
【问题描述】:

尽可能简单地说,我有以下表结构:

Date | Type | Title

假设Type 是一个 1-10 范围内的值,我在表中有 1000 条记录,我想要最近 5 条唯一类型的记录。所以结果会是这样的:

             Date | Type | Title
2009-06-04 14:32:00 | 4 | Zeppo
2009-06-04 14:31:00 | 2 | Groucho
2009-06-04 14:30:00 | 8 | Harpo
2009-06-04 14:29:00 | 5 | Gummo
2009-06-04 14:28:00 | 3 | Chico

似乎我要么希望DISTINCT 仅适用于Type 列,要么我希望GROUP BY 将在 ORDER BY 子句之后应用。

全部在 MySQL 4 中。

【问题讨论】:

  • Gummo 的类型应该有2 吗?

标签: sql mysql


【解决方案1】:

我错过了什么吗?简单的解决方案似乎是:

SELECT  MAX(date) AS max_date, type, title
FROM    table
GROUP BY
        type  
ORDER BY
        max_date DESC
LIMIT 5

而且应该非常快。

【讨论】:

  • @Adam:我认为你的解决方案正是作者真正的意思,但它并没有像他说的那样返回“每种类型的 5 条最新记录” i>.
  • @Adam:但我认为这是一个 +1。
【解决方案2】:

没有针对MySQL 4 进行测试,但在MySQL 5 中可以轻松完成。

您需要在您的表中添加某种PRIMARY KEY 才能使其正常工作。

SELECT  l.*
FROM    (
        SELECT  type,
                COALESCE(
                (
                SELECT  id
                FROM    mytable li
                WHERE   li.type= dlo.type
                ORDER BY
                        li.type DESC, li.date DESC, li.id DESC
                LIMIT 4, 1
                ), CAST(0xFFFFFFFF AS DECIMAL)) AS mid
                COALESCE(
                (
                SELECT  date
                FROM    mytable li
                WHERE   li.type= dlo.type
                ORDER BY
                        li.type DESC, li.date DESC, li.id DESC
                LIMIT 4, 1
                ), '9999-31-12') AS mdate
        FROM    (
                SELECT  DISTINCT type
                FROM    t_mytable dl
                ) dlo
        ) lo, t_mytable l
WHERE   l.type >= lo.type
        AND l.type  <= lo.type
        AND (l.date, l.id) >= (lo.mdate, lo.mid)

有关其工作原理的更多详细信息,请参阅我的博客中的此条目:

如果您无法添加PRIMARY KEY 来实现此解决方案,您可以尝试使用效率较低的系统变量:

SELECT  l.*
FROM    (
        SELECT  @lim := 5,
                @cg := -1
        ) vars,
        mytable l
WHERE   CASE WHEN @cg <> type THEN @r := @lim ELSE 1 END > 0
        AND (@r := @r - 1) >= 0
        AND (@cg := type) IS NOT NULL
ORDER BY
        type DESC, date DESC

这里有描述:

更新:

如果您不想为每种类型选择5 记录(这将在结果集中给出5 x number of types 记录),而是想选择具有不同类型的5 最新记录(这将给出@987654336 @结果集中的记录),使用这个查询:

SELECT  date, type, title
FROM    mytable m
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    mytable mi
        WHERE   mi.date > m.date
                AND mi.type = m.type
        )
ORDER BY
        date DESC
LIMIT 5

如果您有很多类型,这将比使用GROUP BY 更有效,前提是您在date 上有一个索引。

【讨论】:

  • 很棒的文章。我确实认为您可以告诉 MySQL 要使用哪个索引,而不是在 Advanced Row Sampling 的底部使用您的技巧:dev.mysql.com/doc/refman/5.1/en/index-hints.html
  • @Adam:将使用索引,但仅用于第一列的粗略过滤以及第二列的 USING WHERE。相信我,该查询的每一行都是故意的:)
【解决方案3】:

假设查询性能有点重要,而你被 MySQL 4 卡住了,我会选择这样的:

SELECT Date, Type, Title
FROM (
    SELECT Date, Type, Title
    FROM Table
    WHERE Type = 1
    ORDER BY Date
    LIMIT 1

    UNION ALL

    SELECT Date, Type, Title
    FROM Table
    WHERE Type = 2
    ORDER BY Date
    LIMIT 1

    ...
) x
ORDER BY Date
LIMIT 5

它并不漂亮,但它应该可以快速完成工作。如果您定期向类型列添加新值,这可能不适合您,因为它需要定期修改查询。

我认为派生表是在 4.1 中添加的,因此您至少需要在 4 系列中达到那么高。如果您使用的是版本 5 或其他数据库,那么会有更好的方法来解决这个问题。

【讨论】:

  • 它是 4.1,所以我可能会查看派生表。不幸的是,类型值会频繁更改,以至于这种方法在维护方面有点痛苦,但这是一种有趣的方法 - 谢谢。
【解决方案4】:

这对于联合语句和嵌套选择来说似乎是一个很好的例子。

类似的东西:

select t.date, t.type, t.title from (Select top 5 table.Date, table.Type, table.Title from table where type = 1 order by table.date desc) as t

union

select t2.date, t2.type, t2.title from (Select top 5 table.Date, table.Type, table.Title from table where type = 2 order by table.date desc) as t2

[...]

select t10.date, t10.type, t10.title from (Select top 5 table.Date, table.Type, table.Title from table where type = 10 order by table.date desc) as t10

order by type, date

不幸的是,我这里只有 sql server 2008 来测试这个,所以 ymmv;但这是非常基本的东西,它应该可以根据参考指南在 mysql 4.0 中支持嵌套选择和联合。 (我已经根据 mysql 文档将 as 子句添加到嵌套的 from 语句中。)

【讨论】:

    【解决方案5】:

    试试这个

    select
        T.*
    from
            (select
                max(date) dt,
                Type
            from
                table
            group by type
            order by dt desc
            limit 5) subQuery 
            inner join table T on T.date = subQuery.dt and T.Type = subQuery.Type
    

    我只在 MySQL 5 上尝试过。这是假设日期字段是唯一的。如果您有除日期以外的主键,请在查询中使用它。

    【讨论】:

      【解决方案6】:

      我知道它有点晚了,但遇到了同样的问题并想出了办法:所以我在发帖。

      SELECT t.Date, t.Type, t.Title
      FROM (SELECT Date, Type, Title FROM table ORDER BY Date DESC) AS t
      GROUP BY t.Type LIMIT 5;
      

      我认为没有更简单的解决方案。

      解释

      1. 首先执行内部 SELECT。这将返回一个表 行,DESC 按日期列排序。在此表中,最新条目为 特定类型高于同一类型的所有其他条目。 此返回表重命名为 t。

      2. 现在基于类型列对此表执行 GROUP BY 操作。 结果将是遇到的第一行,每种类型。

      3. 现在添加一个限制条件 获取前 5 行。

      【讨论】:

        猜你喜欢
        • 2013-01-17
        • 2015-10-18
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        相关资源
        最近更新 更多