通过分组事务更新列
Posted
技术标签:
【中文标题】通过分组事务更新列【英文标题】:updating columns by grouping transactions 【发布时间】:2014-09-08 17:25:17 【问题描述】:我在对象集合 col_a 中有以下数据:
00004719~BBK~US
00004719~SBK~US
00004719~OBK~GB
00004719~IBK~DE
00004720~BBK~US
00004720~SBK~GB
00004725~IBK~IN
Col_a 在数据库中定义为:
create OR REPLACE TYPE col_a AS TABLE OF varchar2(100)
我需要根据上述数据更新 upd_tbl (col_bbk,col_sbk,col_ibk,col_obk) 中的 4 列,以便: 如果 col_a 包含 BBK,则使用事务的 ~ 分隔符的第三个值更新 col_bbk;如果 col_a 包含 SBK,则类似地为事务更新 col_sbk。 事务编号由 col_a 中第一次出现的 ~ 子字符串标识。
transaction_number 是 upd_tbl 中的 pk,upd_tbl 和集合数据之间存在一对多的关系。但是,该集合将 transaction_number 作为其元素的一部分。
transaction_number = regexp_substr(col_a, '[^~]+', 1, 1)
需要输出:对于事务“00004719”,col_bbk = US,col_SBK = US,col_obk = GB,col_ibk = DE。
我目前正在循环中逐行更新各个 col_a 值。 本质上,对于同一个事务“00004719”,更新会根据代码(SBK 等)触发 4 次。
是否可以一次为每个事务编写一次此更新?
以下内容不断出现“sql 命令未正确结束”错误。
UPDATE upd_tbl
SET ctry_bbk = (CASE
WHEN regexp_substr(tam.column_value, '[^~]+', 1, 2) = 'BBK' THEN regexp_substr(tam.column_value, '[^~]+', 1, 3)
ELSE NULL
END),
ctry_sbk = CASE
WHEN regexp_substr(tam.column_value, '[^~]+', 1, 2) = 'SBK' THEN regexp_substr(tam.column_value, '[^~]+', 1, 3)
ELSE NULL
END,
ctry_ibk = CASE
WHEN regexp_substr(tam.column_value, '[^~]+', 1, 2) = 'IBK' THEN regexp_substr(tam.column_value, '[^~]+', 1, 3)
ELSE NULL
END,
ctry_obk = (CASE
WHEN regexp_substr(tam.column_value, '[^~]+', 1, 2) = 'OBK' THEN regexp_substr(tam.column_value, '[^~]+', 1, 3)
ELSE NULL
END)
from (select column_value from table(col_a('00004719~BBK~US','00004719~SBK~US','00004719~IBK~GB','00004719~OBK~IN','00004720~BBK~US','00004720~SBK~RU','00004725~BBK~US'))) tam
where upd_tbl.transaction_number = regexp_substr(tam.column_value, '[^~]+', 1, 1);
【问题讨论】:
谢谢。但是,如果 col_a 值在对象集合类型中怎么办?我尝试过这样的事情。我无法在 cmets 中使用我的解决方案。所以,编辑了这个问题。 再次检查。向数据透视表添加了合并。 【参考方案1】:这是一个枢轴方法:
select
transaction,
"'BBK'",
"'SBK'",
"'OBK'",
"'IBK'"
from (
select
regexp_substr("col_a", '[^~]+', 1, 1) as transaction,
regexp_substr("col_a", '[^~]+', 1, 2) as code,
regexp_substr("col_a", '[^~]+', 1, 3) as country
from Table1 t)
pivot
(
MAX(country) for code in ('BBK','SBK','OBK','IBK')
);
这是fiddle i'm working with。
特别感谢@Lawrence 和@Bulat 的their help in finishing the idea,我只需要MAX
来聚合而不是COUNT
在枢轴上。
要使用枢轴创建多列更新,如下所示:
我已经让它合并和更新同一个表,但是将它设置为不同的表就像调整第一个合并/更新语句一样简单。
MERGE INTO Table1 t1
USING
(
select
"transactionid",
"'BBK'",
"'SBK'",
"'OBK'",
"'IBK'"
from (
select
regexp_substr("col_a", '[^~]+', 1, 1) as "transactionid",
regexp_substr("col_a", '[^~]+', 1, 2) as code,
regexp_substr("col_a", '[^~]+', 1, 3) as country
from Table1 t)
pivot
(
MAX(country) for code in ('BBK','SBK','OBK','IBK')
)
) ta ON (regexp_substr(t1."col_a", '[^~]+', 1, 1) = ta."transactionid" )
WHEN MATCHED THEN UPDATE
SET "col_bbk" = ta."'BBK'",
"col_sbk" = ta."'SBK'",
"col_obk" = ta."'OBK'",
"col_ibk" = ta."'IBK'",
"transactionid" = ta."transactionid";
Here is a fiddle 正在使用此合并更新支点。
【讨论】:
优秀。谢谢。它工作得很好。之前没有考虑过使用数据透视...我也让它与正常更新一起使用: UPDATE upd_table1 SET (ctry_bbk,ctry_sbk,ctry_ibk,ctry_obk) = (上面的数据透视查询) where transactionid = table1.transaction_number );使用合并更新与典型更新相比有什么特定优势吗? According to some,merge 是 oracle 的做法。它还有助于思考比常规插入然后更新更快的 upsert(插入/更新)。 谢谢。这肯定是一个赞成票,我会这样标记它。在我的例子中,没有插入的范围,它只是一个更新操作因此,现在一个简单的更新就足够了。如果存在性能瓶颈,我总是可以按照您的建议将其更改为仅包含更新部分的合并。但是,谢谢。枢轴解决方案很棒。以上是关于通过分组事务更新列的主要内容,如果未能解决你的问题,请参考以下文章