2010-02-18 49 views
2

我是Oracle分析函數的新手,我試圖找到編寫我的查詢的最佳方法。棘手的Oracle分析函數問題

以下是我的工作......


CREATE TABLE my_table 
(
    pid   NUMBER NOT NULL, 
    my_value  NUMBER, 
    value_date DATE NOT NULL, 

    CONSTRAINT pk_my_table PRIMARY KEY (pid, value_date) 
); 

注意,「value_date」是主鍵的一部分的表的簡化版本。

對於每個「PID」,我想查詢顯示5列:
1. PID
2.「MY_VALUE」的爲最近7天的數據的
3.最大值對於7天最大相應天數(value_date)
4.「MY_VALUE」數據的最最近30天
5.相應天(value_date)的在30天的最大

的最大價值在於它沒有連接可能做到這一點?什麼是完成這個最好的方法?

在此先感謝您的幫助,

卡爾

回答

3

我無法得到我在這裏尋找的答案,所以我在Oracle論壇上發佈了這個問題。我得到的答案正是我所期待的。下面通過查詢表,沒有任何連接得到的答案只有一個通...


    SELECT pid, 
      MAX(CASE 
        WHEN value_date > TRUNC (SYSDATE) - 6 THEN my_value 
        ELSE 0 
       END) 
       max_7_days, 
      MAX(value_date) 
       KEEP (DENSE_RANK FIRST ORDER BY 
             (CASE 
              WHEN value_date > 
                TRUNC (SYSDATE) - 6 
              THEN 
               my_value 
              ELSE 
               0 
             END) DESC) 
       day_7_days, 
      MAX(CASE 
        WHEN value_date > TRUNC (SYSDATE) - 29 THEN my_value 
        ELSE 0 
       END) 
       max_30_days, 
      MAX(value_date) 
       KEEP (DENSE_RANK FIRST ORDER BY 
             CASE 
              WHEN value_date > 
                TRUNC (SYSDATE) - 29 
              THEN 
               my_value 
              ELSE 
               0 
             END DESC) 
       day_30_days 
    FROM my_table 
GROUP BY pid; 

櫃面有人想測試一下,這裏是一些樣本數據。


INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 300, '18-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 200, '17-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 4500, '16-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 800, '15-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 12000, '14-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 21000, '13-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 5600, '12-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 18400, '11-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 7200, '10-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 24000, '09-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 8800, '08-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 6000, '07-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 44200, '06-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 2800, '05-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 58500, '04-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 8000, '03-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 30600, '02-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 7200, '01-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 62700, '31-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 48000, '30-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 16800, '29-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 83600, '28-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 18400, '27-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 16800, '26-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 40000, '25-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 23400, '24-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 99900, '23-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 67200, '22-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 5800, '21-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 57000, '20-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 96100, '19-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 64000, '18-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 52800, '17-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 71400, '16-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 14000, '15-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 7200, '14-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 111000, '13-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 64600, '12-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 113100, '11-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (1, 84000, '10-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 6000, '18-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 7800, '17-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 13500, '16-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 25600, '15-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 276000, '14-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 210000, '13-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 162400, '12-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 36800, '11-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 86400, '10-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 480000, '09-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 8800, '08-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 102000, '07-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1237600, '06-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 61600, '05-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1287000, '04-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 144000, '03-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 275400, '02-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 93600, '01-FEB-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1630200, '31-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1248000, '30-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 235200, '29-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,3176800, '28-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 73600, '27-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 403200, '26-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 200000, '25-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 280800, '24-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 599400, '23-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1612800, '22-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 110200, '21-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1653000, '20-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,2498600, '19-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,2368000, '18-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 211200, '17-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,2570400, '16-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 224000, '15-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 223200, '14-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2, 999000, '13-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,2325600, '12-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,1017900, '11-JAN-10'); 
INSERT INTO my_table (pid, my_value, value_date) VALUES (2,2352000, '10-JAN-10'); 

謝謝大家爲回答這個問題所做的努力!

卡爾

2

我認爲這是給你正確的解決方案。我剛剛在瀏覽器中輸入了它,並沒有經過測試。我想這應該幫助你......至少試圖給你出個主意......

SELECT table_7_day_info.pid 
     ,table_7_day_info.max_val_7_day 
     ,table_7_day_info.max_day_7_day 
     ,table_30_day_info.max_val_30_day 
     ,table_30_day_info.max_day_30_day 
FROM 
    (
     SELECT t1.pid, t1.my_value max_val_7_day, t1.value_date max_day_7_day 
     FROM my_table t1 
     WHERE (t1.pid,t.my_value) in (
            SELECT t.pid, max(t.my_value) 
            FROM my_table t 
            WHERE t.value_date >= sysdate - 7 
            GROUP BY t.pid 
            ) 
    ) table_7_day_info, 
    (
     SELECT t2.pid, t2.my_value max_val_30_day, t2.value_date max_day_30_day 
     FROM my_table t2 
     WHERE (t2.pid,t2.my_value) in (
            SELECT t3.pid, max(t3.my_value) 
            FROM my_table t3 
            WHERE t3.value_date >= sysdate - 30 
            GROUP BY t3.pid 
            ) 
    ) table_30_day_info, 
WHERE table_7_day_info.pid = table_7_day_info.pid 
+1

感謝Zango的。我很欣賞這種努力,但我正在嘗試使用分析函數來避免嵌套查詢和多次訪問同一個表。 – Kal 2010-02-18 19:39:36

1

您可以在相同的時間間隔內一個通獲取信息。即最近7天的信息以及最近30天的信息。但是,這些數據扎堆,你需要一個連接:

select nvl(week.pid,mon.pid) 
    , week.week_val 
    , week.week_date 
    , mon.month_val 
    , mon.month_date 
    from (
     select pid 
       , max(my_value) month_val 
       , max(value_date) keep (dense_rank last order by my_value) month_date 
      from my_table 
      where value_date >= sysdate - 30 
      group by pid 
     ) mon 
     left outer join 
     (
     select pid 
       , max(my_value) week_val 
       , max(value_date) keep (dense_rank last order by my_value) week_date 
      from my_table 
      where value_date >= sysdate - 7 
      group by pid 
     ) week 
     on (mon.pid = week.pid) 
; 

這裏我用左外連接,因爲它可能是你有一個星期之內沒有數據,但有一個月之內的一些數據。

0
SELECT A.PID,A.VALUE_DATE_7DYMAX, A.MY_VALUE, B.VALUE_DATE_30DYMAX, B.MY_VALUE FROM (SELECT * FROM (select pid,my_value, VALUE_DATE AS VALUE_DATE_7DYMAX, row_number() over(partition by pid order by MY_VALUE desc) rn FROM MY_TABLE 
where value_date between TO_DATE('11-JAN-10','DD-MON-YY') AND TO_DATE('21-JAN-10','DD-MON-YY'))where RN =1) A , 
(SELECT * FROM (select pid,my_value, VALUE_DATE AS VALUE_DATE_30DYMAX, row_number() over(partition by pid order by MY_VALUE desc) rn FROM MY_TABLE 
where value_date between TO_DATE('11-JAN-10','DD-MON-YY') AND TO_DATE('21-FEB-10','DD-MON-YY'))where RN =1) B 
WHERE A. PID =B.PID 
+0

這裏我使用Rownum Analytical函數來實現它。 – 2013-11-06 08:48:51

-1
select t.*, 
    max(my_value) over(partition by pid order by value_date range between 0 preceding and 7 following) recent7value, 
    max(value_date) over(partition by pid order by value_date range between 0 preceding and 7 following) recent7date, 
    max(my_value) over(partition by pid order by value_date range between 0 preceding and 30 following) recent30value, 
    max(value_date) over(partition by pid order by value_date range between 0 preceding and 30 following) recent30date 
from my_table t 
order by pid, 
    value_date; 
0

此解決方案僅涉及2次表傳球和不使用硬編碼日期。

我已經使用了2個子查詢使用row_number()基本上基於value_date進行排序,以分別獲取7天範圍和30天範圍內的最近日期。使用該數據集根據最大值my_value對記錄進行排序,挑選排名等於1的最高記錄,並獲得最大值&對應的日期。

SELECT daytab7.pid, maxval_7day,maxvaldate_7day,maxval_30day,maxvaldate_30day 
FROM 
    ( /*picking top-most ranked value and corresp. date*/ 
    SELECT PID, MY_VALUE MAXVAL_7DAY, VALUE_DATE MAXVALDATE_7DAY 
    FROM  
    ( /*Assigning rank for range filtered values*/ 
    SELECT PID, MY_VALUE, VALUE_DATE, RANK() OVER(PARTITION BY PID ORDER BY MY_VALUE DESC) RNK 
    FROM 
     ( /*assigning row_number by ordering rows by value_date desc to get recent data for specified range of 7 days*/ 
     SELECT PID, MY_VALUE, VALUE_DATE, 
     ROW_NUMBER() OVER(PARTITION BY PID ORDER BY VALUE_DATE DESC) ROW_NUM 
     FROM MY_TABLE 
     ORDER BY 1, 3 DESC 
     ) 
    WHERE ROW_NUM <= 7 
    ) 
    WHERE RNK = 1 
) daytab7, 
    ( /*picking top-most ranked value and corresp. date*/ 
    SELECT PID, MY_VALUE MAXVAL_30DAY, VALUE_DATE MAXVALDATE_30DAY 
    FROM  
    ( /*Assigning rank for range filtered values*/ 
    SELECT PID, MY_VALUE, VALUE_DATE, RANK() OVER(PARTITION BY PID ORDER BY MY_VALUE DESC) RNK 
    FROM 
     ( /*assigning row_number by ordering rows by value_date desc to get recent data for specified range of 30 days*/ 
     SELECT PID, MY_VALUE, VALUE_DATE, ROW_NUMBER() OVER(PARTITION BY PID ORDER BY VALUE_DATE DESC) ROW_NUM 
     FROM MY_TABLE 
     ORDER BY 1, 3 DESC 
     ) 
    WHERE ROW_NUM <= 30 
    ) 
    WHERE RNK = 1 
) daytab30 
WHERE daytab7.pid = daytab30.pid 

這裏是輸出:

PID | MAXVAL_7DAY | MAXVALDATE_7DAY | MAXVAL_30DAY | MAXVALDATE_30DAY 
1 | 21000 | 8/13/2015 | 99900 | 7/23/2015  
2 | 276000 | 8/14/2015 | 3176800 | 7/28/2015 
+1

感謝muddyfish和mogsdad幫助修復格式化...因爲這是我的第一個答案,因此無法弄清楚如何使用提供的提示正確格式化 – 2015-08-28 12:37:11

+0

已更改樣本數據一點點通過更新年和月到2015年7月/ 8月,以檢查使用上述基於sysdate的解決方案會得到什麼結果...但後來在日期中找到了一種通用方法。 – 2015-08-28 12:41:00