使用最新日期在oracle中选择某些记录

时间:2015-04-14 09:57:12

标签: sql oracle greatest-n-per-group

所以我目前有一种方法可以做我想做的事情:

SELECT * FROM 
( SELECT  
e.*,
ROW_NUMBER() OVER (partition by USER_ID order by COPIED_TIMESTAMP DESC) r
FROM  
TABLE  e)
WHERE r = 1;

这很好用,但如果表变大,我觉得可能存在性能问题。我在看这样的事情:

SELECT MAX(COPIED_TIMESTAMP), USER_ID
              FROM TABLE
              GROUP BY USER_ID

这也有效,但有没有办法显示所有信息,而不仅仅是时间戳和ID。我对SQL / Oracle查询很陌生,在这个问题上有点迷失。

3 个答案:

答案 0 :(得分:1)

  

但如果表格变大,我觉得可能存在性能问题。

我认为分析查询很好,因为它只会扫描一次。您可以通过创建索引(如果需要)来进一步优化其性能。

您的第二个查询将仅返回timestamp和user_id列,但是,当您需要其他列时,无论如何都要执行多个表扫描。所以,这不是一个好主意。

如果您正在寻找其他选项,例如 NOT EXISTS ,则仍需要多次表扫描。

让我们看一个小测试用例:

分析查询

SQL> EXPLAIN PLAN FOR SELECT * FROM
  2  (SELECT e.*,
  3    ROW_NUMBER() OVER (partition BY deptno order by hiredate DESC) r
  4  FROM emp e
  5  ) WHERE r = 1;

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 3291446077

---------------------------------------------------------------------------------
| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |    14 |  1400 |     3   (0)| 00:00:01 |
|*  1 |  VIEW                    |      |    14 |  1400 |     3   (0)| 00:00:01 |
|*  2 |   WINDOW SORT PUSHED RANK|      |    14 |   518 |     3   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL     | EMP  |    14 |   518 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("R"=1)
   2 - filter(ROW_NUMBER() OVER ( PARTITION BY "DEPTNO" ORDER BY
              INTERNAL_FUNCTION("HIREDATE") DESC )<=1)

17 rows selected.

SQL>

NOT EXISTS查询

SQL> EXPLAIN PLAN FOR
  2  SELECT *
  3  FROM emp t1
  4  WHERE NOT EXISTS (SELECT 1 FROM emp t2
  5                    WHERE t1.deptno = t2.deptno
  6                      and t2.hiredate > t1.hiredate);

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 3353202012

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    48 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN ANTI    |      |     1 |    48 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |   518 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| EMP  |    14 |   154 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."DEPTNO"="T2"."DEPTNO")
       filter("T2"."HIREDATE">"T1"."HIREDATE")

16 rows selected.

SQL>

因此,您可以看到分析查询仅执行一次表扫描

答案 1 :(得分:0)

返回not exists相同ID的行以及更晚的时间戳:

SELECT USER_ID, COPIED_TIMESTAMP, other_column1, other_column2
FROM TABLE t1
WHERE NOT EXISTS (select 1 from table t2
                  where t1.user_id = t2.user_id
                    and t2.COPIED_TIMESTAMP > t1.COPIED_TIMESTAMP)

答案 2 :(得分:0)

Analytic functions是你的朋友:

SELECT MAX( COPIED_TIMESTAMP ) KEEP ( DENSE_RANK LAST ORDER BY COPIED_TIMESTAMP ) AS COPIED_TIMESTAMP,
       MAX( other_column     ) KEEP ( DENSE_RANK LAST ORDER BY COPIED_TIMESTAMP ) AS other_column,
       MAX( other_column2    ) KEEP ( DENSE_RANK LAST ORDER BY COPIED_TIMESTAMP ) AS other_column2,
       USER_ID
FROM   TABLE_NAME
GROUP BY USER_ID