Complex select in loop(基于之前的解决方案)
Complex select in loop (based on a previous solution)
我在这里问了一个问题:
我得到了一个完美的答案,但现在我需要在复杂的 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
问题是列数和源 table 可能会有所不同,因此我正在寻找一种灵活的解决方案,我可以将其用于任何存在 phone_number 列的复杂查询。我已经尝试过的:
将整个select放入循环并加入到
SELECT ic.country
FROM int_codes ic
WHERE ic.int_code = substr(t1.phone_number, 1, i)
作为子查询,但显然不能工作,因为它没有存储,没有字段可以填充
在过程中创建一个视图并将国家加入其中,但它不灵活
- 没试过,但想过一个有很多 UNION 和 NOT EXISTS 的脚本,但是 运行
会非常复杂和缓慢
- 使用 CURSOR,但错误消息说我必须在架构级别定义 TYPE,但由于确定的 table 结构,它仍然不灵活。
那么我应该怎么做呢?
(如果有人有完全不同的方法来灵活地在 table 中识别和显示 phone 数字,欢迎他们)
--更新--
解决方法:
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)
);
如果您使用的是 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 table
使用正确的国家代码和名称,以这种方式(假设 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 table 有一些主键列(在下面的查询中,此列名为 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 ........ ;
我在这里问了一个问题:
我得到了一个完美的答案,但现在我需要在复杂的 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
问题是列数和源 table 可能会有所不同,因此我正在寻找一种灵活的解决方案,我可以将其用于任何存在 phone_number 列的复杂查询。我已经尝试过的:
将整个select放入循环并加入到
SELECT ic.country FROM int_codes ic WHERE ic.int_code = substr(t1.phone_number, 1, i)
作为子查询,但显然不能工作,因为它没有存储,没有字段可以填充
在过程中创建一个视图并将国家加入其中,但它不灵活
- 没试过,但想过一个有很多 UNION 和 NOT EXISTS 的脚本,但是 运行 会非常复杂和缓慢
- 使用 CURSOR,但错误消息说我必须在架构级别定义 TYPE,但由于确定的 table 结构,它仍然不灵活。
那么我应该怎么做呢?
(如果有人有完全不同的方法来灵活地在 table 中识别和显示 phone 数字,欢迎他们)
--更新--
解决方法:
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)
);
如果您使用的是 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 table
使用正确的国家代码和名称,以这种方式(假设 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 table 有一些主键列(在下面的查询中,此列名为 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 ........ ;