通过分组事务更新列

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(插入/更新)。 谢谢。这肯定是一个赞成票,我会这样标记它。在我的例子中,没有插入的范围,它只是一个更新操作因此,现在一个简单的更新就足够了。如果存在性能瓶颈,我总是可以按照您的建议将其更改为仅包含更新部分的合并。但是,谢谢。枢轴解决方案很棒。

以上是关于通过分组事务更新列的主要内容,如果未能解决你的问题,请参考以下文章

事务对象和命令对象

更新及事务处理

通过对它们进行分组来获取重复的 Id

SQL Server查询优化和事务处理

事务属性及事务分组

Firestore 事务在单个事务中更新多个文档