2016-07-28 104 views
0

這是我對源數據的插入語句。如何根據上一行和下一行刪除記錄並根據特定條件分配日期

REM INSERTING into EXPORT_TABLE 
SET DEFINE OFF; 
Insert into EXPORT_TABLE values ('4VKMH','GUIDFREE','UPSELL',to_date('11-MAR-14 17:05:35','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-14 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('11-JUN-14 23:59:00','DD-MON-YY HH24:MI:SS'),92,0); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','UPSELL',to_date('11-MAR-14 17:05:35','DD-MON-YY HH24:MI:SS'),to_date('12-JUN-14 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('10-MAR-15 23:59:00','DD-MON-YY HH24:MI:SS'),271,73.78); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDFREE','EXPIRATION',to_date('12-JUN-14 01:26:26','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-14 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('11-JUN-14 23:59:00','DD-MON-YY HH24:MI:SS'),92,0); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','RENEWAL',to_date('11-MAR-15 01:23:01','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-15 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('10-MAR-16 23:59:00','DD-MON-YY HH24:MI:SS'),365,99); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','CANCELLATION',to_date('11-MAR-15 03:11:09','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-15 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-15 23:59:00','DD-MON-YY HH24:MI:SS'),0,-99); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','UPSELL',to_date('16-MAR-15 10:49:34','DD-MON-YY HH24:MI:SS'),to_date('16-MAR-15 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('10-MAR-16 23:59:00','DD-MON-YY HH24:MI:SS'),360,97.92); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','CANCELLATION',to_date('22-FEB-16 18:19:00','DD-MON-YY HH24:MI:SS'),to_date('16-MAR-15 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('22-FEB-16 23:59:00','DD-MON-YY HH24:MI:SS'),343,-4.61); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','NEW SUBSCRIPTION',to_date('23-FEB-16 13:08:05','DD-MON-YY HH24:MI:SS'),to_date('23-FEB-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('22-FEB-18 23:59:00','DD-MON-YY HH24:MI:SS'),730,178);  
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','CANCELLATION',to_date('23-FEB-16 15:16:44','DD-MON-YY HH24:MI:SS'),to_date('23-FEB-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('23-FEB-16 23:59:00','DD-MON-YY HH24:MI:SS'),0,-178); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDGWA','UPSELL',to_date('23-FEB-16 15:22:42','DD-MON-YY HH24:MI:SS'),to_date('23-FEB-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('22-MAR-16 23:59:00','DD-MON-YY HH24:MI:SS'),28,0); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDGWA','CANCELLATION',to_date('11-MAR-16 04:25:50','DD-MON-YY HH24:MI:SS'),to_date('23-FEB-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('11-MAR-16 23:59:00','DD-MON-YY HH24:MI:SS'),17,0); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','UPSELL',to_date('14-MAR-16 10:02:05','DD-MON-YY HH24:MI:SS'),to_date('14-MAR-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('13-APR-16 23:59:00','DD-MON-YY HH24:MI:SS'),30,8.41); 
Insert into EXPORT_TABLE values ('4VKMH','GUIDPAID','UPSELL',to_date('11-APR-16 09:33:06','DD-MON-YY HH24:MI:SS'),to_date('14-APR-16 00:00:00','DD-MON-YY HH24:MI:SS'),to_date('13-MAR-17 23:59:00','DD-MON-YY HH24:MI:SS'),333,90.59); 

我有我的源數據

REG_ID | PRODUCT_CD | EVENT_TYPE  | EVENT_DATE   | TERM_START_DATE | TERM_END_DATE  | DAYS | AMT 
--------+------------+-----------------+--------------------+--------------------+--------------------+------+-------- 
4VKMH | GUIDFREE | UPSELL   | 11-MAR-14 17:05:35 | 11-MAR-14 00:00:00 | 11-JUN-14 23:59:00 | 92 | 0 
4VKMH | GUIDPAID | UPSELL   | 11-MAR-14 17:05:35 | 12-JUN-14 00:00:00 | 10-MAR-15 23:59:00 | 271 | 73.78 
4VKMH | GUIDFREE | EXPIRATION  | 12-JUN-14 01:26:26 | 11-MAR-14 00:00:00 | 11-JUN-14 23:59:00 | 92 | 0 
4VKMH | GUIDPAID | RENEWAL   | 11-MAR-15 01:23:01 | 11-MAR-15 00:00:00 | 10-MAR-16 23:59:00 | 365 | 99  * 
4VKMH | GUIDPAID | CANCELLATION | 11-MAR-15 03:11:09 | 11-MAR-15 00:00:00 | 11-MAR-15 23:59:00 | 0 | -99 
4VKMH | GUIDPAID | UPSELL   | 16-MAR-15 10:49:34 | 16-MAR-15 00:00:00 | 10-MAR-16 23:59:00 | 360 | 97.92 
4VKMH | GUIDPAID | CANCELLATION | 22-FEB-16 18:19:00 | 16-MAR-15 00:00:00 | 22-FEB-16 23:59:00 | 343 | -4.61 
4VKMH | GUIDPAID | NEW SUBSCRIPTION| 23-FEB-16 13:08:05 | 23-FEB-16 00:00:00 | 22-FEB-18 23:59:00 | 730 | 178 
4VKMH | GUIDPAID | CANCELLATION | 23-FEB-16 15:16:44 | 23-FEB-16 00:00:00 | 23-FEB-16 23:59:00 | 0 | -178 
4VKMH | GUIDGWA | UPSELL   | 23-FEB-16 15:22:42 | 23-FEB-16 00:00:00 | 22-MAR-16 23:59:00 | 28 | 0 
4VKMH | GUIDGWA | CANCELLATION | 11-MAR-16 04:25:50 | 23-FEB-16 00:00:00 | 11-MAR-16 23:59:00 | 17 | 0 
4VKMH | GUIDPAID | UPSELL   | 14-MAR-16 10:02:05 | 14-MAR-16 00:00:00 | 13-APR-16 23:59:00 | 30 | 8.41 
4VKMH | GUIDPAID | UPSELL   | 11-APR-16 09:33:06 | 14-APR-16 00:00:00 | 13-MAR-17 23:59:00 | 333 | 90.59 

此數據由REG_ID已經排序,EVENT_DATE,並TERM_START_DATE

我試圖產生從這個輸出:

REG_ID | PRODUCT_CD | EVENT_TYPE  | EVENT_DATE   | TERM_START_DATE | TERM_END_DATE  | DAYS | AMT 
--------+------------+-----------------+--------------------+--------------------+--------------------+------+-------- 
4VKMH | GUIDFREE | UPSELL   | 11-MAR-14 17:05:35 | 11-MAR-14 00:00:00 | 11-JUN-14 23:59:00 | 92 | 0 
4VKMH | GUIDPAID | UPSELL   | 11-MAR-14 17:05:35 | 12-JUN-14 00:00:00 | 10-MAR-15 23:59:00 | 271 | 73.78 
4VKMH | GUIDFREE | EXPIRATION  | 12-JUN-14 01:26:26 | 11-MAR-14 00:00:00 | 11-JUN-14 23:59:00 | 92 | 0 
4VKMH | GUIDPAID | UPSELL   | 16-MAR-15 10:49:34 | 16-MAR-15 00:00:00 | 22-FEB-16 23:59:00 | 360 | 97.92 
4VKMH | GUIDPAID | CANCELLATION | 22-FEB-16 18:19:00 | 16-MAR-15 00:00:00 | 22-FEB-16 23:59:00 | 343 | -4.61 
4VKMH | GUIDGWA | UPSELL   | 23-FEB-16 15:22:42 | 23-FEB-16 00:00:00 | 11-MAR-16 23:59:00 | 28 | 0 
4VKMH | GUIDGWA | CANCELLATION | 11-MAR-16 04:25:50 | 23-FEB-16 00:00:00 | 11-MAR-16 23:59:00 | 17 | 0 
4VKMH | GUIDPAID | UPSELL   | 14-MAR-16 10:02:05 | 14-MAR-16 00:00:00 | 13-APR-16 23:59:00 | 30 | 8.41 
4VKMH | GUIDPAID | UPSELL   | 11-APR-16 09:33:06 | 14-APR-16 00:00:00 | 13-MAR-17 23:59:00 | 333 | 90.59 

這是通過其結果是從原始數據得出的邏輯:

對於每個記錄EVENT_TYPE'RENEWAL''UPSELL''NEW SUBSCRIPTION':如果以下記錄BEVENT_TYPE'CANCELLATION',則:

  1. 如果記錄具有相同EVENT_DATE日期部分爲(忽略時間),同時消除記錄從結果。所以這就是記錄4,5,8和9被淘汰的原因。
  2. 否則,如果記錄具有比記錄一個較早TERM_END_DATE值,更新一個TERM_END_DATE的。所以這就是爲什麼記錄10已更新TERM_END_DATE

我曾嘗試使用下面的SQL,並得到一個問題ORA-00933來處理我的第一個條件:SQL命令不能正確地結束

  (SELECT REG_ID, 
      EVENT_TYPE, 
      EVENT_DATE, 
      PRODUCT_CD, 
      TERM_START_DATE, 
      TERM_END_DATE, 
      LAG(EVENT_TYPE, 1, '-') over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as PREV_EVENT_TYPE, 
      LAG(EVENT_DATE, 1) over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as PREV_EVENT_DATE, 
      LEAD(EVENT_TYPE, 1, '-') over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as NEXT_EVENT_TYPE, 
      LEAD(EVENT_DATE, 1) over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as NEXT_EVENT_DATE 
      from mytable)TEMP 
      WHERE NOT (TEMP.event_type = 'CANCELLATION' AND (TEMP.PREV_EVENT_TYPE = 'NEW SUBSCRIPTION' OR TEMP.PREV_EVENT_TYPE = 'RENEWAL' OR 
      TEMP.PREV_EVENT_TYPE = 'UPSELL') and TEMP.EVENT_DATE <> TEMP.PREV_EVENT_DATE) 
      AND 
      NOT ((TEMP.PREV_EVENT_TYPE = 'NEW SUBSCRIPTION' OR TEMP.PREV_EVENT_TYPE = 'RENEWAL' OR 
      TEMP.PREV_EVENT_TYPE = 'UPSELL') AND TEMP.EVENT_DATE <> TEMP.NEXT_EVENT_DATE AND TEMP.NEXT_EVENT_TYPE = 'CANCELLATION') 
+0

爲什麼-1爲我的問題?這個問題有什麼不對嗎? – beckham

+1

我懷疑缺乏細節,看這裏https://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ – TheGameiswar

+0

嗨Gameiswar - 我是新的論壇。你能否讓我知道缺少哪些細節。根據我的理解,我已經清楚地說明了所有要求。請幫幫我。 – beckham

回答

2

您在查詢中出現錯誤的原因是,在定義子查詢之前,您必須指明要從中選擇的內容。因此,如果您以select * from爲前綴,那將是一個有效的查詢。

請注意,您不必執行那些or操作,因爲使用in運算符可以縮短操作時間。

你也應該否定一些比較(因爲你已經有NOT)和截斷日期TRUNC

下面是該查詢我建議:

SELECT  TEMP.REG_ID, 
      TEMP.EVENT_TYPE, 
      TEMP.EVENT_DATE, 
      TEMP.PRODUCT_CD, 
      TEMP.TERM_START_DATE, 
      CASE WHEN TEMP.EVENT_TYPE IN ('NEW SUBSCRIPTION', 'RENEWAL', 'UPSELL') 
        AND TEMP.NEXT_EVENT_TYPE = 'CANCELLATION' THEN 
         LEAST(TEMP.TERM_END_DATE, TEMP.NEXT_TERM_END_DATE) 
       ELSE TEMP.TERM_END_DATE 
      END AS TERM_END_DATE, 
      TEMP.DAYS, 
      TEMP.AMT 
FROM (SELECT  REG_ID, 
        EVENT_TYPE, 
        EVENT_DATE, 
        PRODUCT_CD, 
        TERM_START_DATE, 
        TERM_END_DATE, 
        DAYS, 
        AMT, 
        LAG(EVENT_TYPE, 1, '-') over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as PREV_EVENT_TYPE, 
        LAG(EVENT_DATE, 1) over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as PREV_EVENT_DATE, 
        LEAD(EVENT_TYPE, 1, '-') over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as NEXT_EVENT_TYPE, 
        LEAD(EVENT_DATE, 1) over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as NEXT_EVENT_DATE, 
        LEAD(TERM_END_DATE, 1) over (
         PARTITION BY REG_ID, PRODUCT_CD 
         ORDER BY EVENT_DATE, TERM_START_DATE) as NEXT_TERM_END_DATE 
      FROM export_table) TEMP 
WHERE NOT (TEMP.EVENT_TYPE = 'CANCELLATION' 
      AND TEMP.PREV_EVENT_TYPE IN ('NEW SUBSCRIPTION', 'RENEWAL', 'UPSELL') 
      AND TRUNC(TEMP.EVENT_DATE) = TRUNC(TEMP.PREV_EVENT_DATE)) 
AND  NOT (TEMP.NEXT_EVENT_TYPE = 'CANCELLATION' 
      AND TEMP.EVENT_TYPE IN ('NEW SUBSCRIPTION', 'RENEWAL', 'UPSELL') 
      AND TRUNC(TEMP.NEXT_EVENT_DATE) = TRUNC(TEMP.EVENT_DATE)) 

注意,term_end_date記錄6也被修改,如第2條規則適用於它。

+0

嗨Trincot - 它工作得很好。 :) – beckham

+0

@ Trincot,我有一個新的問題,我一直試圖從過去的36小時。我有一個查詢是拋出一個錯誤,我無法修復它。如果你有一段時間你可以看看嗎? – beckham

+0

@ Trincot - 我有一個新的問題,很容易。如果只有你有一些時間。 :) http://stackoverflow.com/questions/39422688/oracle-left-outer-join-with-where-clause/39422762?noredirect=1#comment66170323_39422762 – beckham

1

讓我預先說明我沒有在Oracle中測試這個功能,因爲我沒有方便的Oracle數據庫。

我將它縮減爲單個連接,將性能與接受的答案進行比較可能很有用。

select 
    e1.reg_id, 
    e1.product_cd, 
    e1.event_type, 
    e1.event_date, 
    e1.term_start_date, 
    case e1.event_type when 'CANCELLATION' then e1.term_end_date else coalesce(e2.term_end_date, e1.term_end_date) end as term_end_date, 
    e1.days, 
    e1.amt 
from event e1 
    left outer join event e2 on 
     e1.reg_id = e2.reg_id and 
     e1.product_cd = e2.product_cd and 
     e1.term_start_date = e2.term_start_date and 
     (e1.event_type = 'CANCELLATION' or e2.event_type = 'CANCELLATION') and 
     e1.event_date <> e2.event_date 
where trunc(e1.event_date) <> trunc(e2.event_date) or e2.reg_id is null 
+0

@beckham,這非常令人驚訝,它在SQL服務器和DB2上運行良好。確保你有一切都完全一樣,並確保DATE()函數在Oracle中可用,它可能是TO_DATE()。 –

+0

@ John Kuhns,我使用了Trunc函數從日期中去除時間戳並且查詢起作用。 :)。你認爲這些性能會隨着這些外連接數量的增加而降低嗎? – beckham

+0

好,現在你可以接受我的答案。歡迎來到StackExchange! –