用户定义的函数,有条件地将文本拆分为 Oracle 列
Posted
技术标签:
【中文标题】用户定义的函数,有条件地将文本拆分为 Oracle 列【英文标题】:User defined function which conditionally splits text into columns Oracle 【发布时间】:2020-08-05 01:55:08 【问题描述】:我是 Oracle 数据库或一般数据库的新手,我遇到的一个案例很快就变成了一个令人头疼的问题
我有一个查询,它对给定客户端的地址 ID 进行分组并返回,每个地址 ID 都有一个关联类型,我需要在单独的列中使用它
我现在的查询返回如下内容:
CLIENT_ID ADDRESS_AGG_TYP
12345 6882|HOME;8273|WORK;3192|OTHER
52345 5523|OTHER;1345|HOME;9547|WORK
74563 4431|OTHER;6456|WORK;7567|HOME
34534 1543|WORK;5634|HOME;5123|OTHER
ADDRESS_AGG_TYP - 是一个 LISTAGG,在 address_id 和地址类型的 concat 之上按客户端 ID 分组
Table 的 ddl 可能看起来有点像这样。
CREATE TABLE addresses
( address_id number(*) primary key,
client_id number(*),
type varchar2(70),
address_line_1 varchar2(70),
address_line_2 varchar2(70)
);
我需要将输出转换成这样的:
CLIENT_ID HOME WORK OTHER
12345 6882 8273 3192
52345 1345 9547 5523
74563 7567 6456 4431
34534 5634 1543 5123
关于如何实现这一点的任何想法?我猜这可能需要某种用户定义的函数,但我似乎无法理解这些。
这是在 Oracle DB 版本 12 C 上
【问题讨论】:
发布表定义和示例数据总是有帮助的。home
、work
和 other
是仅有的三种可能的地址类型吗?每个客户最多只能拥有一个吗?
请分享构造CLIENT_ID和ADDRESS_AGG_TYP两列的ddl
@JustinCave 有 5 种可能的类型,每个客户只有一个可能的条目。
@GeorgeJoseph - 添加了地址表的 ddl 让我知道这是否有帮助。
您在问题中写道:Table 的 ddl 可能看起来有点像这样你知道Oracle Data Dictionary
【参考方案1】:
这是一种使用正则表达式和指令的方法。
首先我附加一个';'到字符串的开头,如数据块所示。
我将正则表达式定义为以 ; 开头的模式后跟数字并以 \HOME 或 \WORK 或 \OTHER 结尾。
然后从提取的部分中,我将其进一步切片以获得数字
with data
as (
select 12345 as client_id,';'||'6882|HOME;8273|WORK;3192|OTHER' as address_agg_typ from dual union all
select 52345 as client_id,';'||'5523|OTHER;1345|HOME;9547|WORK' as address_agg_typ from dual union all
select 74563 as client_id,';'||'4431|OTHER;6456|WORK;7567|HOME' as address_agg_typ from dual union all
select 34534 as client_id,';'||'1543|WORK;5634|HOME;5123|OTHER' as address_agg_typ from dual
)
select client_id
,substr(
regexp_substr(address_agg_typ,';[0-9]*\|HOME')
,2
,instr(regexp_substr(address_agg_typ,';[0-9]*\|HOME'),'HOME')
-3
) as home_extract
,substr(
regexp_substr(address_agg_typ,';[0-9]*\|WORK')
,2
,instr(regexp_substr(address_agg_typ,';[0-9]*\|WORK'),'WORK')
-3
) as work_extract
,substr(
regexp_substr(address_agg_typ,';[0-9]*\|OTHER')
,2
,instr(regexp_substr(address_agg_typ,';[0-9]*\|OTHER'),'OTHER')
-3
) as other_extract
from data
+-----------+--------------+--------------+---------------+
| CLIENT_ID | HOME_EXTRACT | WORK_EXTRACT | OTHER_EXTRACT |
+-----------+--------------+--------------+---------------+
| 12345 | 6882 | 8273 | 3192 |
| 52345 | 1345 | 9547 | 5523 |
| 74563 | 7567 | 6456 | 4431 |
| 34534 | 5634 | 1543 | 5123 |
+-----------+--------------+--------------+---------------+
db 小提琴链接
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=41a7a4fb3286326b1cb0baf1512aca1b
【讨论】:
这看起来很棒!完美运行!以上是关于用户定义的函数,有条件地将文本拆分为 Oracle 列的主要内容,如果未能解决你的问题,请参考以下文章