【问题标题】:Finding the lowest value in a table greater than a certain value查找表中大于某个值的最小值
【发布时间】:2010-10-20 14:57:40
【问题描述】:

假设我有以下数据

Name      Value
===============
Small        10
Medium      100
Large      1000

想象这些代表盒子的体积。我有一些物品想放在盒子里,我想要尽可能小的盒子。我需要一个 SQL 查询:

  1. 返回最小行大于我的查询参数的行
  2. 如果没有这样的行,则返回最大的行。

很容易将其拆分为两个查询(即首先查询点 1,如果没有返回行,则从表中选择最大的数字)。但是,如果可能的话,我喜欢在一个查询中做一些事情以消除开销(代码和上下文切换),而且看起来应该可以做到。这可能很明显,但是太阳一整天都在照耀着我,我无法思考!

例如,如果您使用 5 的参数,我希望查询返回 10,如果您使用 15 的参数,则返回 100,如果您使用任何大于 100(包括大于 1000 的数字)的参数,则返回 1000。

我使用的是 Oracle 11g,所以任何特殊的 Oracle 优点都可以。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:
    SELECT  *
    FROM    (
            SELECT  *
            FROM    (
                    SELECT  *
                    FROM    mytable
                    WHERE   value > 10000
                    ORDER BY
                            value
                    )
            UNION ALL
            SELECT  *
            FROM    (
                    SELECT  *
                    FROM    mytable
                    ORDER BY
                            value DESC
                    )
            )
    WHERE   rownum = 1
    

    这将有效地使用mytable(value)COUNT(STOPKEY) 上的索引。

    有关性能详情,请参阅我的博客中的这篇文章:

    【讨论】:

      【解决方案2】:
      SELECT MAX(Value)
      FROM Table
      WHERE Value <= LEAST(@param,(SELECT MAX(Value) FROM Table))
      

      我对 Oracle 不太熟悉,但我确信它具有 LEAST 功能或类似功能。

      无论如何,此查询的子查询将在Value 列上具有正确的索引。

      说真的,您真的应该在两个查询中执行此操作(或者如果您想将它们保持在同一个位置,则在一个存储过程中执行两个步骤),因为如果第一个查询有效,则第二个查询是不必要的。将它们组合在一个查询中必然会为您提供无条件的第二个(或子)查询。您必须查询该表两次,所以问题是您是总是查询两次还是仅在必要时查询。

      【讨论】:

        【解决方案3】:

        只是为了好玩,我假设目标尺寸来自包裹表,并且您想找到一堆包裹的盒子。如果第一个值为 NULL,COALESCE 选择第二个值。

        SELECT  
            p.pkgid,  
            p.pkgsize,  
            COALESCE(MIN(b1.size), MAX(b2.size) AS boxsize    
        FROM packages AS p  
        LEFT JOIN boxes AS b1 ON p.pkgsize < b1.boxsize  
        LEFT JOIN boxes AS b2  -- yes, a cartesian join 
        GROUP BY p.pkgid, p.pkgsize
        

        作为与其他解决方案比较的单个语句,使用

        SELECT  
            COALESCE(MIN(b1.size), MAX(b2.size) AS boxsize    
        FROM Table AS t1,  
             Table AS t2   
        WHERE targetsize < t1.Value
        

        【讨论】:

          【解决方案4】:
          WITH ranges_table AS
               (SELECT     LEVEL * 100 AS range_value
                      FROM DUAL
                CONNECT BY LEVEL <= 20)
          SELECT MIN (range_value)
            FROM ranges_table
           WHERE range_value >= 5 OR range_value = (SELECT MAX (range_value)
                                                      FROM ranges_table)
          

          【讨论】:

            【解决方案5】:

            这行得通。将“5”替换为您的参数。

            select min(basket_value) as basket_value
            from baskets
            where basket_value > 5 
               or basket_value = (select max(basket_value) from baskets)
            

            生成测试数据的简单脚本:

            create table baskets(
              basket_name varchar2(20)
             ,basket_value number
            );
            
            insert into baskets(basket_name,basket_value) values('Small',10);
            insert into baskets(basket_name,basket_value) values('Medium',100);
            insert into baskets(basket_name,basket_value) values('Large',1000);
            commit;
            
            --drop table baskets;  --run when finished
            

            【讨论】:

              【解决方案6】:
              select a.newvalue from (
              select MIN(value) as newvalue, 1 as order  From table where value > @param
              union select MAX(value) as newvalue, 2 as order from table) A
              order by a.order
              

              【讨论】:

              • 是的,但所需的值始终是第一行。
              猜你喜欢
              • 2018-06-27
              • 2018-06-19
              • 1970-01-01
              • 2012-04-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-09-16
              • 2015-01-16
              相关资源
              最近更新 更多