2015-09-28 88 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