Oracle SQL:从字段分隔的记录分隔的字符串列分析事务金额
我在oracle sql表中有两列,其中许多重要的事务信息以一种不太容易检索的方式存储。数据集有两列trxn_a和trxn_b trxn_a: 2019-01-25~现金存款~5000美元~John Doe#2019-01-26~现金存款~1000美元~John Doe# trxn_b: 2019-01-25~现金存款~3000美元~John Doe#2019-01-25~现金存款~1500美元~John Doe#2019-01-26~现金存款~100美元~John Doe#2019-01-26~现金存款~800美元~John Doe#2019-01-26~现金存款~100美元~John Doe# 正如您看到的,字段由Oracle SQL:从字段分隔的记录分隔的字符串列分析事务金额,sql,oracle,Sql,Oracle,我在oracle sql表中有两列,其中许多重要的事务信息以一种不太容易检索的方式存储。数据集有两列trxn_a和trxn_b trxn_a: 2019-01-25~现金存款~5000美元~John Doe#2019-01-26~现金存款~1000美元~John Doe# trxn_b: 2019-01-25~现金存款~3000美元~John Doe#2019-01-25~现金存款~1500美元~John Doe#2019-01-26~现金存款~100美元~John Doe#2019-01-26
~
分隔,记录由#
分隔。可以有任意数量的事务(因此,单元格中可以有任意数量的#
)
上面列出的数据只是两列(即两个单元格)中的一条数据记录
我的目标是将这些数据转换成多行,每行都是按日期计算的总和(trxn\u amount)
。请参见以下所需输出:
date, trxn_amt_a, trxn_amt_b
2019-01-25, 5000, 4500
2019-01-26, 1000, 1000
我尝试了INSTR
和SUBSTR
函数,但这对于处理这种数据结构中的变量来说并不强大。另外,我不知道如何:
使用
REGEXP\u SUBSTR
拆分
上的记录。此外,我不知道您如何在op中添加另一列,因为您在输入中没有。只需Replace(字符串“~cash-deposit~”、“,”下面的“)
这是一个复杂的问题。下面是我如何进行的一步一步的描述
第一部分是使用
#
分隔符将每个值拆分为行。为此,我们使用REGEXP\u SUBSTR()
以及connectby
来生成递归
select trim(regexp_substr(trxn_a,'[^#]+', 1, level) ) trxn_a, level
from mytable
connect by regexp_substr(trxn_a, '[^#]+', 1, level) is not null
然后,我们需要将每个结果值解析为列。只需使用一系列
REGEXP\u SUBSTR()
即可完成此操作。需要特别注意包含金额值的列,该列包含非数字字符(“$5000”
):需要删除无效字符,以便以后可以将该值视为数字
注意:出于您的目的,您实际上不需要从值中恢复所有4列(日期和金额足够);我将显示所有列,以防您需要访问另一列
select
'ta' src,
regexp_substr(trxn_a,'[^~]+', 1, 1) tdate,
regexp_substr(trxn_a,'[^~]+', 1, 2) ttype,
replace(regexp_substr(trxn_a,'[^$~]+', 1, 3), ',', '') tamount,
regexp_substr(trxn_a,'[^~]+', 1, 4) tuser
from (
select trim(regexp_substr(trxn_a,'[^#]+', 1, level) ) trxn_a, level
from mytable
connect by regexp_substr(trxn_a, '[^#]+', 1, level) is not null
)
源表中的每一列(
trxn_a
,trxn_b
)都必须单独处理,因为每个值都会生成随机数目的记录。结果可以UNION
ed,然后外部查询执行条件聚合:
最后一个问题:
with t as (
select
'ta' src,
regexp_substr(trxn_a,'[^~]+', 1, 1) tdate,
regexp_substr(trxn_a,'[^~]+', 1, 2) ttype,
replace(regexp_substr(trxn_a,'[^$~]+', 1, 3), ',', '') tamount,
regexp_substr(trxn_a,'[^~]+', 1, 4) tuser
from (
select trim(regexp_substr(trxn_a,'[^#]+', 1, level) ) trxn_a, level
from mytable
connect by regexp_substr(trxn_a, '[^#]+', 1, level) is not null
)
union all
select
'tb' src,
regexp_substr(trxn_b,'[^~]+', 1, 1) tdate,
regexp_substr(trxn_b,'[^~]+', 1, 2) ttype,
replace(regexp_substr(trxn_b,'[^$~]+', 1, 3), ',', '') tamount,
regexp_substr(trxn_b,'[^~]+', 1, 4) tuser
from (
select trim(regexp_substr(trxn_b,'[^#]+', 1, level) ) trxn_b, level
from mytable
connect by regexp_substr(trxn_b, '[^#]+', 1, level) is not null
)
)
select
tdate,
SUM(DECODE(src, 'ta', tamount, 0)) trxn_amt_a,
SUM(DECODE(src, 'tb', tamount, 0)) trxn_amt_b
from t
group by tdate;
根据您的测试数据,产生:
TDATE TRXN_AMT_A TRXN_AMT_B
2019-01-25 5000 4500
2019-01-26 1000 1000
哇,我觉得你很痛。我希望这不是你的设计?可能可以用一些正则表达式来解。是的。不是我的设计。事实上,这就是数据如何以xml格式存储在节点的单元格中。我必须从这里取出来,trxn_a和trxn_b是输入表中的两列,因此在输出表中,我喜欢这个解决方案。我唯一在想的是,我们是否能在任何情况下避免工会。
TDATE TRXN_AMT_A TRXN_AMT_B
2019-01-25 5000 4500
2019-01-26 1000 1000