【问题标题】:SQL - How to select a row having a column with max valueSQL - 如何选择具有最大值列的行
【发布时间】: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 行,每行都有该特定日期的最大值。请协助我。

标签: sql oracle


【解决方案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;
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-11-10
          • 2021-08-16
          • 1970-01-01
          • 1970-01-01
          • 2011-12-06
          相关资源
          最近更新 更多