我在这里问了一个问题: Identify phone numbers in a PL/SQL iteration
我得到了一个完美的答案,但现在我需要在一个复杂的选择语句中使用它。
目标与加入查询的列中的结果相同。例如:
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)
作为子查询,但它显然无法正常工作,因为它没有存储,没有要填写的字段
在程序中创建一个视图并将国家/地区加入其中,但它不灵活
那我该怎么做呢?
(如果有人采用完全不同的方法在表格中灵活地识别和显示电话号码,我们欢迎他们)
- 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)
);
答案 0 :(得分:1)
如果您使用的是Oracle 12c,则可以使用LATERAL VIEW
使用子查询来确定正确的国家/地区代码:
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;
;
-----编辑-----
在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 ........ ;