2015-09-28 70 views
0

我在這裏問了一個問題: Identify phone numbers in a PL/SQL iteration複雜的SELECT環路(基於以前的解決方案)

,我得到了一個完美的答案,但現在我需要在一個複雜的SELECT語句中使用它。

目標與連接到查詢的列中的結果相同。例如:

SELECT t1.phone_number 
     , t2.origin_country 
     , sum(t1.volume) Total_vol 
     , sum(t1.charge) Total_chg 
     from t2 
    LEFT JOIN t1 ON t1.item_no = t2.item_no 
    LEFT JOIN t3 ON t3.vcode = t2.vcode 
    LEFT JOIN /*<<Here should be a subquery which attach the column with 
    the countries to my query>>*/ 
     +many WHERE and GROUP BY clauses 

的問題是列和源表可以變化的數量,因此,我尋找一個靈活的解決方案,我可以與將PHONE_NUMBER列中存在任何複雜的查詢中使用。我已經嘗試過:

  • 把整個選擇進入一個循環,並加入到

    SELECT ic.country 
    FROM int_codes ic 
    WHERE ic.int_code = substr(t1.phone_number, 1, i) 
    

    一個子查詢,但因爲它沒有存儲不能明顯地工作,沒有任何字段填寫

  • 創建一個步驟的圖,並加入國家,但它不是靈活

  • 沒有嘗試過,但想到有許多UNION腳本和NOT EXISTS,但它瓦特應該會非常複雜並且運行速度很慢並且運行速度很慢
  • 與CURSOR,但是錯誤消息說我必須在模式級別上定義TYPE,但由於確定的表結構,它仍然不靈活。

那麼我該怎麼做呢?

(如果有人有一個完全不同的方法來識別和顯示的電話號碼錶中的靈活歡迎他們)

--UPDATE--

解決辦法:

select ... PHONE_NUMBER, XY, ZZ, ... , 
     case 
     when i.INT_CODE = substr(PHONE_NUMBER,1,4) then i.COUNTRY 

     when i.INT_CODE = substr(PHONE_NUMBER,1,3) 
     and i.INT_CODE = substr(PHONE_NUMBER,1,4) then i.COUNTRY 

     when i.INT_CODE = substr(PHONE_NUMBER,1,2) 
     and i.INT_CODE = substr(PHONE_NUMBER,1,3) then i.COUNTRY 

     when i.INT_CODE = substr(PHONE_NUMBER,1,1) 
     and i.INT_CODE = substr(PHONE_NUMBER,1,2) then i.COUNTRY 

     else 'Unidentified location' 
     end TARGET_COUNTRY 

    from (
      select ... t1.phone_number ,sum(xy) Total XY, sum(zz) ZZ, ... 
      /*same fields like in the main query above*/ 
      left join t2 on ... 
      left join t3 on ... 

      where date = 'some date' and country in ('country1','country2') ... 
      /*many conditions*/ 
      group by t2.phone_number, 
        t3.account ... 
     ) MainQuery 

    left join int_codes i 
    on ( i.INT_CODE = substr(MainQuery.PHONE_NUMBER, 1, 1) 
     or i.INT_CODE = substr(MainQuery.PHONE_NUMBER, 1, 2) 
     or i.INT_CODE = substr(MainQuery.PHONE_NUMBER, 1, 3) 
     or i.INT_CODE = substr(MainQuery.PHONE_NUMBER, 1, 4) 
    ); 

回答

1

如果您使用的是Oracle 12c,那麼您可以使用子查詢的橫向視圖
以確定正確的國家代碼:

SELECT ......... 
FROM T_NUMBERS t 
LEFT JOIN .............. 
LEFT JOIN ................ 
, /* this comma is required by the syntax */ 
LATERAL (
    SELECT * FROM int_codes i 
    WHERE i.INT_CODE = substr(t.PHONE_NUMBER, 1, 1) 
    OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 2) 
    OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 3) 
    OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 4) 
    ORDER BY length(i.INT_CODE) DESC 
    FETCH FIRST 1 ROWS ONLY 
) 
GROUP BY .....; 

此外,假設T_NUMBERS具有唯一標識每一行的一些主鍵列,那麼你可以同時使用這個子查詢用MERGE語句更新T_NUMBERS表
有正確的國家代碼和名稱,在此方式(假設PK是主鍵列):

MERGE INTO T_NUMBERS t 
USING (
    SELECT t.pk, i.country, i.int_code 
    FROM T_NUMBERS t, 
    LATERAL (
    SELECT * FROM int_codes i 
    WHERE i.INT_CODE = substr(t.PHONE_NUMBER, 1, 1) 
     OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 2) 
     OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 3) 
     OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 4) 
    ORDER BY length(i.INT_CODE) DESC 
    FETCH FIRST 1 ROWS ONLY) i 
) i 
ON (t.pk = i.pk) 
WHEN MATCHED THEN UPDATE SET t.COUNTRY = i.COUNTRY, t.COUNTRY_CODE = i.int_CODE; 
; 

----- ----- EDIT

上的Oracle 11g中,您可以嘗試像下面
- 但仍然假設是T_NUMBERS表中有一些主鍵列(在此列下面的查詢被命名爲pk):

SELECT ........ 
FROM (
     SELECT t.pk, t.phone_number, 
      i.int_code, i.country, 
      aaa.*, bbb.* 
      row_number() over(partition by pk order by length(i.int_code) desc) xxxx 
     FROM T_NUMBERS t 
     LEFT JOIN aaa ...... 
     LEFT JOIN bbb ...... 
     LEFT JOIN int_codes i 
     ON ( i.INT_CODE = substr(t.PHONE_NUMBER, 1, 1) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 2) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 3) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 4) 
     ) 
) 
WHERE xxxx = 1 
GROUP BY ........ ; 

我不是確定它會如何執行,可能會很慢。你的答案

SELECT ........ 
FROM (
     SELECT t.pk, t.phone_number, 
      i.int_code, i.country, 
      row_number() over(partition by pk order by length(i.int_code) desc) xxxx 
     FROM T_NUMBERS t 

     LEFT JOIN int_codes i 
     ON ( i.INT_CODE = substr(t.PHONE_NUMBER, 1, 1) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 2) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 3) 
      OR i.INT_CODE = substr(t.PHONE_NUMBER, 1, 4) 
     ) 
) 
LEFT JOIN aaa ...... 
LEFT JOIN bbb ...... 
WHERE xxxx = 1 
GROUP BY ........ ; 
+0

感謝:

以下版本可能稍微好一點的執行。不,不幸的是11g,但正如我所看到的,在12c發佈之前,LATERAL VIEW已經早已存在了。但它不適用於此語法,錯誤消息: 「ORA-00936:缺少的表達式」或 「SQL命令沒有正確結束」 取決於我在哪裏插入LATERAL節。 – A117

+0

我已經用Oracle 11g的一些提案更新了我的答案。 – krokodilko

+0

我最近正在測試你的代碼,但我必須找出如何替換主鍵,因爲沒有任何。與我正在工作的服務器的連接速度非常慢,所以我應該進一步優化。 – A117

相關問題