用户定义的函数,有条件地将文本拆分为列 Oracle

User defined function which conditionally splits text into columns Oracle

我是 Oracle 数据库或一般数据库的新手,我遇到了一个案例,这个案例很快变成了一个令人头疼的问题

我有一个查询,该查询对给定客户端的 returns 地址 ID 进行分组,每个地址 ID 都有一个关联类型,我需要在单独的列中显示该类型

我现在的查询returns是这样的:

   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 的连接之上按客户端 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 结尾。

然后我从提取的部分进一步切分得到数字

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 fiddle link

https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=41a7a4fb3286326b1cb0baf1512aca1b