用户定义的函数,有条件地将文本拆分为 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 上

【问题讨论】:

发布表定义和示例数据总是有帮助的。 homeworkother 是仅有的三种可能的地址类型吗?每个客户最多只能拥有一个吗? 请分享构造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 列的主要内容,如果未能解决你的问题,请参考以下文章

XSLT - 根据长度很好地将长地址拆分为多个标签

如何根据 Oracle SQL 中的某些条件将列拆分为 2?

是否可以将条件传递给 Oracle 用户定义函数?

如何将oracle 中一条数据拆分成多条

在黄瓜 jvm 中,如何正确地将步骤拆分为多个文件?

在 Angular 中,如何有效地将输入项拆分为数组