获取与一列的MAX值对应的其他列?

时间:2011-07-24 15:52:43

标签: mysql join group-by max

好的,这是我的问题:

SELECT
  video_category,
  video_url,
  video_date,
  video_title,
  short_description,
  MAX(video_id) 
FROM
  videos
GROUP BY
  video_category

当它拉取数据时,我得到了video_id的正确行,但它为其他类别拉出了第一行。因此,当我获得类别1的video_id的最大结果时,我得到最大ID,但是表格中的第一行是网址,日期,标题和描述。

如何让它拉出与最大ID结果相对应的其他列?

编辑:修正。

SELECT
    *
FROM
    videos
WHERE
    video_id IN
    (
        SELECT
            DISTINCT
            MAX(video_id)
        FROM
            videos
        GROUP BY
            video_category
    ) 
ORDER BY
    video_category ASC

5 个答案:

答案 0 :(得分:36)

我会尝试这样的事情:

SELECT
   s.video_id
   ,s.video_category
   ,s.video_url
   ,s.video_date
   ,s.video_title
   ,short_description
FROM videos s
   JOIN (SELECT MAX(video_id) AS id FROM videos GROUP BY video_category) max
      ON s.video_id = max.id

这比你自己的解决方案快得多

答案 1 :(得分:7)

我在这里参加聚会很晚,但是我刚刚发表了一篇博客,介绍了我已经使用了几年的方法,并且我想与世界分享。

我将此方法称为“标量汇总比较” ,它是迄今为止实现此目的的性能最高的方法和最简单的方法(以DB引擎术语而言),因为它不需要连接,不需要子查询,并且没有CTE。

对于您的查询,它看起来像这样:

SELECT
  video_category,
  MAX(video_id) AS video_id,
  SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS video_url,
  SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_date)), 12) AS video_date,
  SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_title)), 12) AS video_title,
  SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), short_description)), 12) AS short_description
FROM
  videos
GROUP BY
  video_category

标量和聚合函数的组合执行以下操作:

  1. LPAD比较标识符,以进行正确的字符串比较(例如,“ 0009”和“ 0025”将正确排名)。我在这里假设一个INT主键将LPADDING限制为11个字符。如果使用BIGINT,则将需要增加它以支持表的序数。如果要在DATETIME字段(固定长度)上进行比较,则无需填充。
  2. 使用输出列对填充的标识符进行CONCAT(这样您将获得“ 0009myvalue”与“ 0025othervalue”)
  3. 使集合总数最大化,将获得“ 0025othervalue”作为获胜者。
  4. 对结果进行SUBSTRING,将截断比较的标识符部分,仅保留值。

如果要检索CHAR以外的其他类型的值,则可能需要在输出上执行附加的CAST,例如如果您希望video_date是DATETIME:

CAST(SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_date)), 12) AS DATETIME)

此方法相对于自联接方法的另一个好处是,您可以合并其他汇总数据(不仅是最新值),甚至可以合并同一查询中的第一项和最后一项,例如

SELECT
    -- Overall totals
    video_category,
    COUNT(1) AS videos_in_category,
    DATEDIFF(MAX(video_date), MIN(video_date)) AS timespan,

    -- Last video details
    MAX(video_id) AS last_video_id,
    SUBSTRING(MAX(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS last_video_url,
    ...

    -- First video details
    MIN(video_id) AS first_video_id,
    SUBSTRING(MIN(CONCAT(LPAD(video_id, 11, '0'), video_url)), 12) AS first_video_url,
    ...

    -- And so on

有关此方法相对于其他旧方法的好处的更多详细信息,请访问我的完整博客文章:https://www.stevenmoseley.com/high-performance-correlated-aggregate-sql-queries-without-ctes

答案 2 :(得分:0)

这是一个更通用的解决方案(处理重复项)

CREATE TABLE test(
  i INTEGER,
  c INTEGER,
  v INTEGER
);


insert into test(i, c, v)
values
(3, 1, 1),
(3, 2, 2),
(3, 3, 3),
(4, 2, 4),
(4, 3, 5),
(4, 4, 6),
(5, 3, 7),
(5, 4, 8),
(5, 5, 9),
(6, 4, 10),
(6, 5, 11),
(6, 6, 12);



SELECT t.c, t.v
FROM test t
JOIN (SELECT test.c, max(i) as mi FROM test GROUP BY c) j ON
  t.i = j.mi AND
  t.c  = j.c
ORDER BY c;

答案 3 :(得分:0)

选择视频类别,视频网址,视频日期,视频标题,简短说明,视频ID 从视频t1 其中video_id位于(SELECT max(video_id)FROM videos t2 WHERE t1.video_category = t2.video_category)中;

请提供您的输入和输出记录,以便可以正确理解和测试它们。

答案 4 :(得分:0)

一个稍微“质朴”的解决方案,但应该做同样的工作:

SELECT
  video_category,
  video_url,
  video_date,
  video_title,
  short_description,
  video_id
FROM
  videos
ORDER BY video_id DESC
LIMIT 1;

换句话说,只需生成一个包含您想要的所有列的表格,对其进行排序,使最大值位于顶部,然后将其切掉,以便只返回一行。