SQL - 如何选择具有最大值列的行

Posted

技术标签:

【中文标题】SQL - 如何选择具有最大值列的行【英文标题】:SQL - How to select a row having a column with max value 【发布时间】:2011-02-20 16:58:39 【问题描述】:
date                 value

18/5/2010, 1 pm        40
18/5/2010, 2 pm        20
18/5/2010, 3 pm        60
18/5/2010, 4 pm        30
18/5/2010, 5 pm        60
18/5/2010, 6 pm        25 

我需要查询具有最大值(值)(即 60)的行。所以,这里我们得到两行。从那开始,我需要当天时间戳最低的行(即 2010 年 5 月 18 日,下午 3 点 -> 60)

【问题讨论】:

谢谢大家。现在,如果日期跨越 10 天,我需要对这 10 天中的每一天进行此查询,从而产生 10 行,每行都有该特定日期的最大值。请协助我。 【参考方案1】:

TOP、LIMIT、ROWNUM、...等关键字是依赖于数据库的。请阅读本文了解更多信息。

http://en.wikipedia.org/wiki/Select_(SQL)#Result_limits

Oracle:可以使用 ROWNUM。

select * from (select * from table 
order by value desc, date_column) 
where rownum = 1;

更具体地回答问题:

select high_val, my_key
from (select high_val, my_key
      from mytable
      where something = 'avalue'
      order by high_val desc)
where rownum <= 1

【讨论】:

+1 对于这个问题,我推荐 ROWNUM 查询。 Oracle 很好地优化了这些类型的查询(即,即使它需要排序,它实际上并没有对整个表进行排序 - 它只是在扫描表时保留最上面的行) - 并且使用适当的索引它甚至不会必须这样做。【参考方案2】:

分析!这样可以避免访问表两次:

SELECT DISTINCT
       FIRST_VALUE(date_col)  OVER (ORDER BY value_col DESC, date_col ASC),
       FIRST_VALUE(value_col) OVER (ORDER BY value_col DESC, date_col ASC)
FROM   mytable;

【讨论】:

从纯教育的角度来看,我很想看看这有什么样的性能差异。从 Toms asktom.oracle 网站,我了解到使用 FIRST_VALUE 会产生大量开销。您是否可以指导我比较它们的一些性能结果? 如果您在 (value_col, date_col) 上有一个索引,您会发现 Oracle 在使用 Sujee 的查询时会做得很好,因为它将使用 COUNT STOPKEY 优化。 它避免了两次扫描表,但它为每一行计算 first_value 列,然后 distinct 将它们全部丢弃,但只有一个。比大多数其他答案更好,但聚合是这里的方法。 是的。 Sujee 击败了我,获得了更好的 ROWNUM 解决方案 :)【参考方案3】:

答案是加一个having子句:

SELECT [columns]
FROM table t1
WHERE value= (select max(value) from table)
AND date = (select MIN(date) from table t2 where t1.value = t2.value)

这应该可以工作,并且无需在日期子句中添加额外的子选择。

【讨论】:

HAVING 子句中的任何非聚合都需要成为 GROUP BY 子句的一部分 好点。我在sybase上测试了我的,它可以让你摆脱它。我修改了答案以适应所需的数据库 嗯...您仍然有一个子选择 - 实际上,其中有两个。 感谢您的反馈,是的,有两个,但标准的替代方法是 AND date = select min(date) from table where value = (select max(value) from table))。我参考 J 布鲁克斯的答案(比这个答案高 3 个)作为证据。通过引用前一个子选择的已经获得的值,您可以保存 1 级嵌套 啊,我明白你现在在说什么了。 ...当然,所有的子选择都是不必要的:)【参考方案4】:
SQL> create table t (mydate,value)
  2  as
  3  select to_date('18/5/2010, 1 pm','dd/mm/yyyy, hh am'), 40 from dual union all
  4  select to_date('18/5/2010, 2 pm','dd/mm/yyyy, hh am'), 20 from dual union all
  5  select to_date('18/5/2010, 3 pm','dd/mm/yyyy, hh am'), 60 from dual union all
  6  select to_date('18/5/2010, 4 pm','dd/mm/yyyy, hh am'), 30 from dual union all
  7  select to_date('18/5/2010, 5 pm','dd/mm/yyyy, hh am'), 60 from dual union all
  8  select to_date('18/5/2010, 6 pm','dd/mm/yyyy, hh am'), 25 from dual
  9  /

Table created.

SQL> select min(mydate) keep (dense_rank last order by value) mydate
  2       , max(value) value
  3    from t
  4  /

MYDATE                   VALUE
------------------- ----------
18-05-2010 15:00:00         60

1 row selected.

问候, 抢。

【讨论】:

很好,但 Oracle 仍会进行全面扫描 - 不幸的是,它无法应用 COUNT STOPKEY 优化:( 是的。并且合乎逻辑,因为要确定某些东西是最大值,您必须全部访问它们,或者像在索引中一样预先订购它们。【参考方案5】:

从技术上讲,这与@Sujee 的答案相同。它还取决于您的 Oracle 版本是否有效。 (我认为这种语法是在 Oracle 12 中引入的??)

SELECT *
FROM   table
ORDER BY value DESC, date_column ASC
FETCH  first 1 rows only;

正如我所说,如果您深入了解,我认为这段代码是由 Oracle 优化器在内部解压缩的,读起来像 @Sujee 的。然而,我是一个漂亮的编码的傻瓜,没有充分理由嵌套select 语句不符合美丽! :-P

【讨论】:

【参考方案6】:

在甲骨文中:

这会根据范围获取表中max(high_val)的key。

select high_val, my_key
from (select high_val, my_key
      from mytable
      where something = 'avalue'
      order by high_val desc)
where rownum <= 1

【讨论】:

【参考方案7】:

在 Oracle 数据库中:

create table temp_test1 (id number, value number, description varchar2(20));

insert into temp_test1 values(1, 22, 'qq');
insert into temp_test1 values(2, 22, 'qq');
insert into temp_test1 values(3, 22, 'qq');
insert into temp_test1 values(4, 23, 'qq1');
insert into temp_test1 values(5, 23, 'qq1');
insert into temp_test1 values(6, 23, 'qq1');

SELECT MAX(id), value, description FROM temp_test1 GROUP BY value, description;

Result:
    MAX(ID) VALUE DESCRIPTION
    -------------------------
    6         23    qq1
    3         22    qq

【讨论】:

【参考方案8】:

最简单的答案是

--建立一个名为“t1”的测试表

create table t1
(date datetime,
value int)

-- 加载数据。 -- 注意:日期格式与问题中不同

insert into t1
Select '5/18/2010 13:00',40
union all
Select '5/18/2010 14:00',20
union all
Select '5/18/2010 15:00',60 
union all
Select '5/18/2010 16:00',30 
union all
Select '5/18/2010 17:00',60 
union all
Select '5/18/2010 18:00',25 

-- 找到最大数量和最小日期的行。

select *
from t1
where value = 
    (select max(value)  from t1)
and date = 
    (select min(date) 
    from t1
    where value = (select max(value)  from t1))

我知道你可以做“TOP 1”的答案,但通常你的解决方案会变得非常复杂,以至于由于某种原因你不能使用它。

【讨论】:

对于这个要求,Oracle 不需要对同一个表进行三个额外的访问。 额外访问权限?这将与这里的其他一些执行计划相同,看起来他们做得更少......但可读性较差。而且我知道 Oracle 没有 TOP 命令。【参考方案9】:

你可以使用这个功能,ORACLE DB

 public string getMaximumSequenceOfUser(string columnName, string tableName, string username)
    
        string result = "";
        var query = string.Format("Select MAX (0)from 1 where CREATED_BY = 2", columnName, tableName, username.ToLower());

        OracleConnection conn = new OracleConnection(_context.Database.Connection.ConnectionString);
        OracleCommand cmd = new OracleCommand(query, conn);
        try
        
            conn.Open();
            OracleDataReader dr = cmd.ExecuteReader();
            dr.Read();
            result = dr[0].ToString();
            dr.Dispose();
        
        finally
        
            conn.Close();
        
        return result;
    

【讨论】:

以上是关于SQL - 如何选择具有最大值列的行的主要内容,如果未能解决你的问题,请参考以下文章

如何编写 SQL 来选择具有每个组的最大值(值)的行?

如何编写sql查询以选择一列中具有最大值的行

选择具有最大值的行,并结合WHERE。 MAX和CAST,在spark.sql中

SQL - 选择具有最匹配列的行

从Oracle SQL中的每个组中选择具有最大值的行[重复]

SQL:根据另一列的值在列上保留一个具有最大值的行