某公司开发人员迁移适配达梦数据库,遇到多表关联更新并且同时更新多张表数据源,最终目的是交换同字段列值,特别之处是符合条件的互换跨行字段值。
当时翻阅SQL官方手册,比较数据库的版本,属于二二年九月份非常新的版本,直接搬码SQL语句到达梦数据库执行会报错'-2965 多表更新时仅支持更新同一个表上的列'
,此问题一直僵持他们一个月左右。
起先,有一个人在本人QQ技术群上询问,当时有点忙搁置那儿没管,再过一段时间又有一人询问类似问题,恰逢手头不忙,专门翻看发来的SQL,一眼望上去,感觉很不符合常理的交换值,就是后边贴的“样例初型”。随后,让他们发一个完整的SQL“样例成型”,再看谓词条件“item1.iOrder < item2.iOrder”,目标结果清晰可知。
-- MySQL数据库(样例初型)
update billitem_base item1 inner join billitem_base item2 on item1.tenant_id = item2.tenant_id
set item1.iOrder = item2.iOrder,item2.iOrder = item1.iOrder;
-- MySQL数据库(样例成型)
update billitem_base item1 inner join billitem_base item2 on item1.tenant_id = item2.tenant_id
set item1.iOrder = item2.iOrder,item2.iOrder = item1.iOrder
where item1.iBillId in (select id from bill_base where cbillno = 'fdtr_allocate_strategy')
and item1.iTplId in (select tpl.id from billtemplate_base tpl inner join bill_base base on tpl.iBillId = base.id where base.cbillno = 'fdtr_allocate_strategy' and tpl.iTplMode = 0)
and item1.cName = 'paymentAccountType'
and item2.iBillId in (select id from bill_base where cbillno = 'fdtr_allocate_strategy')
and item2.iTplId in (select tpl.id from billtemplate_base tpl inner join bill_base base on tpl.iBillId = base.id where base.cbillno = 'fdtr_allocate_strategy' and tpl.iTplMode = 0)
and item2.cName = 'payment_currency_name'
and item1.iOrder < item2.iOrder;
TIP:提取公共项代码,减少表重复扫描,尽量提前过滤掉大量数据,并且采用CTE语法格式,优化逻辑层次结构,提高访问效率。
首次检索出符合待交换的目标数据,事前记录(截图)交换前的状态,以作交换前后的参照对比。
交换预期结果:rowid(70) iOrder(22.0) 与 rowid(2) iOrder(24.0) 这两行的iOrder数据需进行交换更新。
update CTMFDTR.billitem_base o,
(
with x0 as (
select i.rowid rid,i.tenant_id, i.iOrder, i.cName from CTMFDTR.billitem_base i
where
i.iBillId in (select id from CTMFDTR.bill_base where cbillno = 'fdtr_allocate_strategy')
and i.iTplId in
(select tpl.id from CTMFDTR.billtemplate_base tpl
inner join CTMFDTR.bill_base base
on tpl.iBillId = base.id
where base.cbillno = 'fdtr_allocate_strategy' and tpl.iTplMode = 0)
),
i1 as (
select * from x0 where cName = 'paymentAccountType'
),
i2 as (
select * from x0 where cName = 'payment_currency_name'
)
select i1.rid rid, i2.iOrder iiOrder
from i1 join i2 on i1.tenant_id = i2.tenant_id
where i1.iOrder < i2.iOrder
union all
select i2.rid rid,i1.iOrder iiOrder
from i1 join i2 on i1.tenant_id = i2.tenant_id
where i1.iOrder < i2.iOrder
) x
set o.iOrder = x.iiOrder
where o.rowid = x.rid;
-- before update
--select iOrder, rowid from CTMFDTR.billitem_base where rowid in(70, 2);
/*
iOrder ROWID
24.0 2
22.0 70
*/
-- after update
/*
iOrder ROWID
22.0 2
24.0 70
*/
成功解决截图