Oracle:Max、partitionby甚至rownum?

Oracle:Max、partitionby甚至rownum?,oracle,subquery,query-optimization,rownum,Oracle,Subquery,Query Optimization,Rownum,我有SQL Server背景,所以我在Oracle方面的技能最低。就性能而言,partitionby似乎优于max。还是使用rownum归档结果表 我有下面的表格 | P_TYPE | TRX_DATE | PROGRAM_NO | REF_NO | SEQ_ID | Select |-------------|----------------|------------|-----------|--------| | 'Local' | 2016/9/5

我有SQL Server背景,所以我在Oracle方面的技能最低。就性能而言,
partitionby
似乎优于
max
。还是使用
rownum
归档结果表

我有下面的表格

| P_TYPE      | TRX_DATE       | PROGRAM_NO | REF_NO    | SEQ_ID |  Select 
|-------------|----------------|------------|-----------|--------|
| 'Local'     | 2016/9/5 14:37 | C1         | null      | E1     |  Yes (latest in Sept 5)
| 'Local'     | 2016/9/5 14:36 | C1         | null      | E1     |
| 'Local'     | 2016/9/5 11:08 | C1         | null      | E1     |
|-------------|----------------|------------|-----------|--------|
| 'Local'     | 2016/9/2 15:16 | C1         | null      | E1     |  Yes (latest in Sept 2)
|-------------|----------------|------------|-----------|--------|
| 'Local'     | 2016/9/1 15:20 | C1         | null      | E1     |  Yes (latest in Sept 1)
| 'Local'     | 2016/9/1 14:33 | C1         | null      | E1     |
|-------------|----------------|------------|-----------|--------|
| '3rd Party' | 2016/9/4 18:00 | null       | D1        | E2     |  Yes
| '3rd Party' | 2016/9/4 17:55 | null       | D1        | E2     |
以下是我想要得到的:

对于列p_类型,如果其值为“Local”,则使用列程序号和序列号。否则,使用参考号和序列号。 如果P_TYPE列中的值相同,请检查TRX_日期。如果列TRX_DATE指示相同的日期,则选择具有最新时间戳的日期。改天?另一个带有最新时间戳的条目

| P_TYPE      | TRX_DATE       | PROGRAM_NO | REF_NO    | SEQ_ID |
|-------------|----------------|------------|-----------|--------|
| 'Local'     | 2016/9/5 14:37 | C1         | null      | E1     |  
| 'Local'     | 2016/9/2 15:16 | C1         | null      | E1     |  
| 'Local'     | 2016/9/1 15:20 | C1         | null      | E1     |  
| '3rd Party' | 2016/9/4 18:00 | null       | D1        | E2     |  
我收到的一个脚本是在
WHERE子句中使用
SELECT MAX

SELECT *
FROM TableW a
WHERE TRX_DATE = 
    CASE P_TYPE
        WHEN 'Local' THEN
            (SELECT MAX(TRX_DATE) FROM TableW
                WHERE PROGRAM_NO = a.PROGRAM_NO AND SEQ_ID = a.SEQ_ID)
        ELSE
            (SELECT MAX(TRX_DATE) FROM TableW
                WHERE REF_NO = a.REF_NO AND SEQ_ID = a.SEQ_ID)
    END
ORDER BY TRX_DATE desc, REF_NO ASC, SEQ_ID;
它起作用了。然而,通过一些研究,似乎按
划分的
成本并没有那么高。参考:

我尝试将查询重写为:

SELECT *
FROM (
SELECT *,
    CASE P_TYPE 
        WHEN 'Local' THEN 
            MAX(TRX_DATE) OVER (PARTITION BY PROGRAM_NO, SEQ_ID)
        ELSE
            MAX(TRX_DATE) OVER (PARTITION BY REF_NO, SEQ_ID)
    END AS MAX_TRX_DATE
FROM TableW
WHERE P_TYPE = 'Local'
)
WHERE TRX_DATE = MAX_TRX_DATE
但是,我只得到以下信息:

| P_TYPE      | TRX_DATE       | PROGRAM_NO | REF_NO    | SEQ_ID |
|-------------|----------------|------------|-----------|--------|
| 'Local'     | 2016/9/5 14:37 | C1         | null      | E1     |  
有什么指引吗。如果可能,请用统计数字说明你的建议。谢谢

编辑:看起来使用行号和分区将大大减少执行计划甚至时间

| CASE             | OPERATION        | CARDINALITY | COST | LAST CR     | LAST ELAPSED  |
|                  |                  |             |      | BUFFER GETS | TIME          |
|------------------|------------------|-------------|------|-------------|---------------|
| 1 - max() in     | SELECT STATEMENT |             |  76  |             |               |
|     where clause | SORT (ORDER BY)  |      1      |  76  |     477     |      3602     |
|------------------|------------------|-------------|------|-------------|---------------|
| 2 - row_number   | SELECT STATEMENT |             |  18  |             |               |
|                  | SORT (ORDER BY)  |      8      |  18  |      53     |       607     |
|------------------|------------------|-------------|------|-------------|---------------|

对于
Local
行,您需要包括定义窗口分区的日期,因为
PROGRAM\u NO,REF\u NO
的所有值对于这些行都是相同的:

select *
from (
  SELECT *,
         CASE P_TYPE
           when 'Local' then 
              row_number() over (partition by program_no, seq_id, trunc(trx_date) order by trx_date desc)
           else 
              row_number() over (partition by ref_no, seq_id order by trx_date desc)
         end as rn
  FROM TableW a
) t
where rn = 1;
在线示例:


(该示例使用Postgres,但除了“忽略”时间戳的时间部分的不同方式外,在Oracle中也是如此)

对于
Local
行,您需要包括定义窗口分区的日期,因为
PROGRAM\u NO,REF\u NO
的所有值对于这些行都是相同的:

select *
from (
  SELECT *,
         CASE P_TYPE
           when 'Local' then 
              row_number() over (partition by program_no, seq_id, trunc(trx_date) order by trx_date desc)
           else 
              row_number() over (partition by ref_no, seq_id order by trx_date desc)
         end as rn
  FROM TableW a
) t
where rn = 1;
在线示例:


(示例使用Postgres,但除了“忽略”时间戳的时间部分的不同方式外,在Oracle中也是一样的)

您是否还需要
TRUNC(trx\u date)
在第二种情况下的
分区依据
子句中?@MT0:我不清楚,因为样本数据没有必要的情况-但可能是的。从OP:yes来看,第三方的实际数据确实显示有具有相同参考号和序列id的行在同一日期。这意味着需要在两个
partitionby
子句上都有
TRUNC(TRX\u DATE)
。对于第二种情况,您是否也需要在
partitionby
子句中都有
TRUNC(TRX\u DATE)
,是。从OP:是,对于第三方,实际数据确实显示有行具有相同的参考编号和序列id,并且在同一日期。这意味着需要在两个
分区上都有
TRUNC(TRX_DATE)