Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql SQL仅选择列上具有最大值的行_Mysql_Sql_Aggregate Functions_Greatest N Per Group_Groupwise Maximum - Fatal编程技术网

Mysql SQL仅选择列上具有最大值的行

Mysql SQL仅选择列上具有最大值的行,mysql,sql,aggregate-functions,greatest-n-per-group,groupwise-maximum,Mysql,Sql,Aggregate Functions,Greatest N Per Group,Groupwise Maximum,我有此文件表(此处为简化版): 身份证件 修订版 内容 1. 1. ... 2. 1. ... 1. 2. ... 1. 3. ... 乍一看。。。 您只需要一个带有MAXaggregate函数的groupby子句: SELECT id, MAX(rev) FROM YourTable GROUP BY id 事情从来没有这么简单,是吗? 我刚刚注意到您还需要内容列 在SQL中,这是一个非常常见的问题:根据某个组标识符在列中查找具有某个最大值的行的整个数据。在我的职业生涯中,我经常听到这样的话

我有此文件表(此处为简化版):

身份证件 修订版 内容 1. 1. ... 2. 1. ... 1. 2. ... 1. 3. ... 乍一看。。。 您只需要一个带有
MAX
aggregate函数的
groupby
子句:

SELECT id, MAX(rev)
FROM YourTable
GROUP BY id
事情从来没有这么简单,是吗? 我刚刚注意到您还需要
内容

在SQL中,这是一个非常常见的问题:根据某个组标识符在列中查找具有某个最大值的行的整个数据。在我的职业生涯中,我经常听到这样的话。事实上,这是我在当前工作的技术面试中回答的问题之一

实际上,StackOverflow社区创建了一个标记来处理这样的问题,这是非常普遍的

基本上,您有两种方法来解决该问题:

与简单的
组标识符联接,组中的最大值
子查询 在这种方法中,首先在子查询中找到
组标识符,即组中的最大值
(上面已经解决)。然后将表加入子查询,并在
组标识符
组中的最大值
上相等:

SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
    SELECT id, MAX(rev) rev
    FROM YourTable
    GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev
左与自连接,调整连接条件和过滤器 在这种方法中,您只需将表本身连接起来。在
组标识符中出现相等。然后,两个聪明的动作:

  • 第二个联接条件是左侧值小于右侧值
  • 执行步骤1时,实际具有最大值的行的右侧将具有
    NULL
    (这是一个
    左连接,记得吗?)。然后,我们过滤连接的结果,只显示右侧为
    NULL
    的行
  • 因此,你最终会:

    SELECT a.*
    FROM YourTable a
    LEFT OUTER JOIN YourTable b
        ON a.id = b.id AND a.rev < b.rev
    WHERE b.id IS NULL;
    
    选择一个*
    从你的桌子上
    左表b
    在a.id=b.id和a.rev
    结论 这两种方法都带来了完全相同的结果

    如果对于
    组标识符
    ,组中有两行的
    最大值
    ,则两种方法的结果中都有这两行

    这两种方法都与SQL ANSI兼容,因此,无论其“风格”如何,都可以与您喜爱的RDBMS一起使用


    这两种方法也都是性能友好的,但是您的里程可能会有所不同(RDBMS、DB结构、索引等)。因此,当您选择一种方法而不是另一种方法时,请选择基准。并确保选择对您最有意义的代码。

    我的偏好是使用尽可能少的代码

    您可以在
    试试这个:

    SELECT * 
    FROM t1 WHERE (id,rev) IN 
    ( SELECT id, MAX(rev)
      FROM t1
      GROUP BY id
    )
    
    在我看来,它不那么复杂。。。更容易阅读和维护。

    像这样的东西

    SELECT yourtable.id, rev, content
    FROM yourtable
    INNER JOIN (
        SELECT id, max(rev) as maxrev
        FROM yourtable
        GROUP BY id
    ) AS child ON (yourtable.id = child.id) AND (yourtable.rev = maxrev)
    

    我不能保证它的性能,但这里有一个技巧,灵感来自微软Excel的局限性。它有一些好的特性

    好东西

    • 即使出现平局,它也应该强制只返回一条“最大记录”(有时有用)
    • 它不需要连接
    方法

    这有点难看,需要您了解rev列的有效值范围。假设我们知道rev列是一个介于0.00和999之间的数字,包括小数,但小数点右侧将只有两位数字(例如,34.17将是一个有效值)

    要点是通过字符串连接/打包主比较字段以及所需的数据来创建一个合成列。通过这种方式,您可以强制SQL的MAX()聚合函数返回所有数据(因为它已打包到单个列中)。然后你必须解包数据

    下面是上面用SQL编写的示例的外观

    SELECT id, 
           CAST(SUBSTRING(max(packed_col) FROM 2 FOR 6) AS float) as max_rev,
           SUBSTRING(max(packed_col) FROM 11) AS content_for_max_rev 
    FROM  (SELECT id, 
           CAST(1000 + rev + .001 as CHAR) || '---' || CAST(content AS char) AS packed_col
           FROM yourtable
          ) 
    GROUP BY id
    
    压缩首先强制rev列为一个已知字符长度的数字,而不考虑rev的值,例如

    • 3.2变为1003.201
    • 57变为1057.001
    • 923.88变为1923.881
    如果操作正确,两个数字的字符串比较应产生与两个数字的数字比较相同的“max”,并且使用substring函数(几乎在任何地方都可以使用一种或另一种形式)很容易将其转换回原始数字。

    这是怎么回事:

    SELECT all_fields.*  
    FROM (SELECT id, MAX(rev) FROM yourtable GROUP BY id) AS max_recs  
    LEFT OUTER JOIN yourtable AS all_fields 
    ON max_recs.id = all_fields.id
    

    另一种解决方案是使用相关子查询:

    select yt.id, yt.rev, yt.contents
        from YourTable yt
        where rev = 
            (select max(rev) from YourTable st where yt.id=st.id)
    
    在(id,rev)上有一个索引会将子查询呈现为一个简单的查找

    以下是与@AdrianCarneiro的答案(子查询,leftjoin)中的解决方案的比较,基于MySQL的测量,InnoDB表有约100万条记录,组大小为:1-3

    对于完整表扫描,子查询/左连接/相关计时相互关联为6/8/9,而对于直接查找或批处理(
    id in(1,2,3)
    ),子查询比其他子查询慢得多(因为重新运行子查询)。然而,我无法在速度上区分leftjoin和相关解决方案


    最后一个注意事项是,由于leftjoin在组中创建n*(n+1)/2个联接,其性能会受到组大小的严重影响…

    此解决方案仅从表中选择一个,因此速度更快。根据sqlfiddle.com上的测试,它只适用于MySQL和SQLite(用于SQLite remove DESC)。也许它可以调整到其他我不熟悉的语言上

    SELECT *
    FROM ( SELECT *
           FROM ( SELECT 1 as id, 1 as rev, 'content1' as content
                  UNION
                  SELECT 2, 1, 'content2'
                  UNION
                  SELECT 1, 2, 'content3'
                  UNION
                  SELECT 1, 3, 'content4'
                ) as YourTable
           ORDER BY id, rev DESC
       ) as YourTable
    GROUP BY id
    

    不是mySQL,但是对于发现这个问题并使用SQL的其他人来说,另一种解决问题的方法是使用MS SQL

    WITH DocIds AS (SELECT DISTINCT id FROM docs)
    
    SELECT d2.id, d2.rev, d2.content
    FROM DocIds d1
    CROSS APPLY (
      SELECT Top 1 * FROM docs d
      WHERE d.id = d1.id
      ORDER BY rev DESC
    ) d2
    

    因为这是关于这个问题最流行的问题,我也会在这里重新发布另一个答案:

    看起来有更简单的方法来实现这一点(但是仅在MySQL中实现):

    请相信中的用户Bohemian的回答,因为它为这个问题提供了如此简洁优雅的答案

    编辑:尽管此解决方案适用于许多p
    select *
    from (select * from mytable order by id, rev desc ) x
    group by id
    
    SELECT 
      id, 
      rev
      -- you can select other columns here
    FROM YourTable t
    WHERE NOT EXISTS (
       SELECT * FROM YourTable t WHERE t.id = id AND rev > t.rev
    )
    
    SELECT id, MAX(rev) AS rev
     , 0+SUBSTRING_INDEX(GROUP_CONCAT(numeric_content ORDER BY rev DESC), ',', 1) AS numeric_content
    FROM t1
    GROUP BY id
    
    with temp as  ( 
    select count(field1) as summ , field1
    from table_name
    group by field1 )
    select * from temp where summ = (select max(summ) from temp)
    
    select t.*
    from test as t
    join
       (select max(rev) as rev
        from test
        group by id) as o
    on o.rev = t.rev
    
    select *
    from platnosci as p
    join firmy as f
    on p.id_rel_firmy = f.id_rel
    join (select max(id_obj) as id_obj
          from firmy
          group by id_rel) as o
    on o.id_obj = f.id_obj and p.od > '2014-03-01'
    
    select id, rev, content
    from
     (select
        @rowNum := if(@prevValue = id, @rowNum+1, 1) as row_num,
        id, rev, content,
        @prevValue := id
      from
       (select id, rev, content from YOURTABLE order by id asc, rev desc) TEMP,
       (select @rowNum := 1 from DUAL) X,
       (select @prevValue := -1 from DUAL) Y) TEMP
    where row_num = 1;
    
    select * from
    (select * from table_name
    order by id,rev desc) temp
    group by id 
    
    SELECT * FROM (SELECT * FROM table1 ORDER BY id, rev DESC) X GROUP BY X.id;
    
    CREATE TABLE table1
        (`id` int, `rev` int, `content` varchar(11));
    
    INSERT INTO table1
        (`id`, `rev`, `content`)
    VALUES
        (1, 1, 'One-One'),
        (1, 2, 'One-Two'),
        (2, 1, 'Two-One'),
        (2, 2, 'Two-Two'),
        (3, 2, 'Three-Two'),
        (3, 1, 'Three-One'),
        (3, 3, 'Three-Three')
    ;
    
    id  rev content
    1   2   One-Two
    2   2   Two-Two
    3   3   Three-Two
    
    SELECT a.id, a.rev, a.contents
      FROM (SELECT id, rev, contents,
                   ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
              FROM YourTable) a
     WHERE a.rank = 1 
    
    SELECT DISTINCT t1.id, MAX(t1.rev), MAX(t2.content)
    FROM Table1 AS t1
    JOIN Table1 AS t2 ON t2.id = t1.id AND t2.rev = (
        SELECT MAX(rev) FROM Table1 t3 WHERE t3.id = t1.id
    )
    GROUP BY t1.id;
    
    id  max(Table1.rev) max(Table2.content)
    1   3   ..d
    2   1   ..b
    
    SELECT *
    FROM
        (SELECT *
        FROM Employee
        ORDER BY Salary DESC)
    AS employeesub
    GROUP BY employeesub.Salary;
    
    SELECT *
    FROM Employee
    WHERE Employee.id = 12345
    ORDER BY Employee.Salary DESC
    LIMIT 1
    
    Select a.id , a.rev, a.content from Table1 a
    inner join 
    (SELECT id, max(rev) rev FROM Table1 GROUP BY id) x on x.id =a.id and x.rev =a.rev
    
    with score as (select max(score_up) from history)
    select history.* from score, history where history.score_up = score.max
    
    SELECT *
    FROM Employee
    where Employee.Salary in (select max(salary) from Employee group by Employe_id)
    ORDER BY Employee.Salary
    
    SELECT A.KEYFIELD1, A.KEYFIELD2, A.FIELD3, A.FIELD4, A.FIELD5
      FROM MYFILE A
     WHERE RRN(A) IN
       (SELECT RRN(B) 
          FROM MYFILE B
         WHERE B.KEYFIELD1 = A.KEYFIELD1 AND B.KEYFIELD2 = A.KEYFIELD2
         ORDER BY B.FIELD5 DESC
         FETCH FIRST ROW ONLY)
    
    CREATE TABLE #temp1
    (
        id varchar(20)
        , rev int
    )
    INSERT INTO #temp1
    SELECT a.id, MAX(a.rev) as rev
    FROM 
        (
            SELECT id, content, SUM(rev) as rev
            FROM YourTable
            GROUP BY id, content
        ) as a 
    GROUP BY a.id
    ORDER BY a.id
    
    SELECT a.id, a.rev, content
    FROM #temp1 as a
    LEFT JOIN
        (
            SELECT id, content, SUM(rev) as rev
            FROM YourTable
            GROUP BY id, content
        ) as b on a.id = b.id and a.rev = b.rev
    GROUP BY a.id, a.rev, b.content
    ORDER BY a.id
    
    SELECT t.*
      FROM
        (
        SELECT id
              ,rev
              ,contents
              ,MAX(rev) OVER (PARTITION BY id) as max_rev
          FROM YourTable
        ) t
      WHERE t.rev = t.max_rev 
    
    SELECT t.*
      FROM
        (
        SELECT id
              ,rev
              ,contents
              ,ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
          FROM YourTable
        ) t
      WHERE t.rank = 1 
    
    SELECT maxRevId & ((1 << 32) - 1) as id, maxRevId >> 32 AS rev
    FROM (SELECT MAX(((rev << 32) | id)) AS maxRevId
          FROM YourTable
          GROUP BY id) x;
    
    select * from docs where (id, rev) IN (select id, max(rev) as rev from docs group by id order by id)  
    
    MyTableAlias = aliased(MyTable)
    newest_records = appdb.session.query(MyTable).select_from(join(
        MyTable, 
        MyTableAlias, 
        onclause=and_(
            MyTable.id == MyTableAlias.id,
            MyTable.version_int < MyTableAlias.version_int
        ),
        isouter=True
        )
    ).filter(
        MyTableAlias.id  == None,
    ).all()