【问题标题】:Getting all row data from minimum value in a field in a SQL query (Oracle)从 SQL 查询 (Oracle) 的字段中的最小值获取所有行数据
【发布时间】:2017-04-05 04:12:09
【问题描述】:

我无法通过指定字段的最小值从 SQL 查询中获取所有信息的行。下面是我正在使用的数据以及我想要获取的数据的基本示例:

SELECT 1 AS NUM_, 'ABC' AS LET_ FROM DUAL
UNION
SELECT 2 AS NUM_, 'DEF' AS LET_ FROM DUAL
UNION
SELECT 3 AS NUM_, 'GHI' AS LET_ FROM DUAL;

上面的查询将产生以下结果:

NUM_ | LET_
-----------
  1  | ABC
  2  | DEF
  3  | GHI

我只想要包含数据1ABC 的行。这是我尝试过的,如下:

SELECT MIN(LN.NUM_) AS MIN_NUM, 
       LN.LET_ 
FROM   (SELECT 1 AS NUM_, 'ABC' AS LET_ FROM DUAL
        UNION
        SELECT 2 AS NUM_, 'DEF' AS LET_ FROM DUAL
        UNION
        SELECT 3 AS NUM_, 'GHI' AS LET_ FROM DUAL) LN
GROUP BY LET_;

但上面仍然给了我所有的行。如何仅将NUM_ 列中值最低的行归零,给我1ABC

【问题讨论】:

    标签: sql oracle group-by subquery min


    【解决方案1】:

    您的查询会找到每个 LET_ 的最小值 NUM_。要在所有记录中获得最小的NUM_,请使用ORDER BY & ROWNUM

    试试这个

    SELECT LN.NUM_ AS MIN_NUM, 
           LN.LET_ 
    FROM   (SELECT 1 AS NUM_, 'ABC' AS LET_ FROM DUAL
            UNION
            SELECT 2 AS NUM_, 'DEF' AS LET_ FROM DUAL
            UNION
            SELECT 3 AS NUM_, 'GHI' AS LET_ FROM DUAL
            ORDER BY LN.NUM_) LN
    Where ROWNUM = 1
    

    【讨论】:

      【解决方案2】:

      在 Oracle 12C 中,您可以使用 ANSI 标准 fetch first row only 语法:

      SELECT 1 AS NUM_, 'ABC' AS LET_ FROM DUAL
      UNION ALL
      SELECT 2 AS NUM_, 'DEF' AS LET_ FROM DUAL
      UNION ALL
      SELECT 3 AS NUM_, 'GHI' AS LET_ FROM DUAL
      ORDER BY 1
      FETCH FIRST 1 ROW ONLY;
      

      【讨论】:

        【解决方案3】:

        正如已经指出的,有不同的方法可以做到这一点:

        一些方法:

        • FETCH FIRST 1 ROW ONLY
        • ORDER BY 在视图中然后 ROWNUM = 1
        • (我的补充)MAX KEEP
        • (我的补充)不相关子查询

        FETCH FIRST 1 ROW ONLY 是最简单的语法,并且性能足够好。但如果你有一张大桌子,其他方法也值得考虑。

        您的数据集太小,无法展示不同的性能结果,所以为了说明它们,让我们用DBA_OBJECTS 创建一个表格。

        create table matt_test as SELECT * FROM dba_objects;
        create unique index matt_test_u1 on matt_test (object_id);
        exec dbms_stats.gather_table_stats(USER, 'MATT_TEST');
        

        然后,尝试一些不同的方法并使用 DBMS_XPLAN 进行测量:

        最大保持

        SELECT MAX (object_id) KEEP (DENSE_RANK FIRST ORDER BY object_id) object_id,
               MAX (object_name) KEEP (DENSE_RANK FIRST ORDER BY object_id) object_name
        FROM   matt_test o;
        
        ------------------------------------------------------------------------------------------
        | Id  | Operation          | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
        ------------------------------------------------------------------------------------------
        |   0 | SELECT STATEMENT   |           |      1 |        |      1 |00:00:00.29 |    8522 |
        |   1 |  SORT AGGREGATE    |           |      1 |      1 |      1 |00:00:00.29 |    8522 |
        |   2 |   TABLE ACCESS FULL| MATT_TEST |      1 |    555K|    555K|00:00:00.12 |    8522 |
        ------------------------------------------------------------------------------------------
        

        FETCH FIRST(注意内存使用)

        SELECT object_id, object_name
        FROM   matt_test o
        order by object_id
        fetch first 1 rows only;
        
        ---------------------------------------------------------------------------------------------------------------------------
        | Id  | Operation                | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
        ---------------------------------------------------------------------------------------------------------------------------
        |   0 | SELECT STATEMENT         |           |      1 |        |      1 |00:00:00.33 |    8522 |       |       |          |
        |*  1 |  VIEW                    |           |      1 |      1 |      1 |00:00:00.33 |    8522 |       |       |          |
        |*  2 |   WINDOW SORT PUSHED RANK|           |      1 |    555K|      1 |00:00:00.33 |    8522 |  2048 |  2048 | 2048  (0)|
        |   3 |    TABLE ACCESS FULL     | MATT_TEST |      1 |    555K|    555K|00:00:00.12 |    8522 |       |       |          |
        ---------------------------------------------------------------------------------------------------------------------------
        

        不相关的子查询

        select object_id, object_name
        from matt_test
        where object_id = ( SELECT min(object_id) FROM matt_test );
        
        -------------------------------------------------------------------------------------------------------
        | Id  | Operation                    | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
        -------------------------------------------------------------------------------------------------------
        |   0 | SELECT STATEMENT             |              |      1 |        |      1 |00:00:00.01 |       7 |
        |   1 |  TABLE ACCESS BY INDEX ROWID | MATT_TEST    |      1 |      1 |      1 |00:00:00.01 |       7 |
        |*  2 |   INDEX UNIQUE SCAN          | MATT_TEST_U1 |      1 |      1 |      1 |00:00:00.01 |       6 |
        |   3 |    SORT AGGREGATE            |              |      1 |      1 |      1 |00:00:00.01 |       3 |
        |   4 |     INDEX FULL SCAN (MIN/MAX)| MATT_TEST_U1 |      1 |      1 |      1 |00:00:00.01 |       3 |
        -------------------------------------------------------------------------------------------------------
        
        Predicate Information (identified by operation id):
        ---------------------------------------------------
        
           2 - access("OBJECT_ID"=)
        

        因此,如果您可以利用索引,您可以看到不相关的子查询可以快得多。 MAX KEEP 方法的性能比FETCH FIRST ROWS 方法好一点,因为它使用的内存更少。

        没有一种最好的方法:每一种都有它的位置。

        如果我在不考虑性能的情况下编写此代码(例如,小型数据集),则默认方法是 FETCH FIRST ROWS

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-04-28
          • 1970-01-01
          • 1970-01-01
          • 2020-05-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多