上下文: 我有两个表:markettypewagerlimitgroups(mtwlg)和stakedistributionindicators(sdi)。当创建一个mtwlg时,在sdi表中创建了两行链接到mtwlg的行 - 每行具有相同的值bar 2,id和另一个字段(让它们称之为X列)必须包含一个0表示一行,1表示另一行。 我们的代码库中存在一个错误,可以自动防止这种情况发生,所以在bug出现的过程中创建的任何mtwlg都没有相关的sdi,导致NPE在各个地方出现。
要解决此问题,需要编写补丁以循环访问mtwlg表,并为每个ID搜索sdi表中的2个相关行。如果存在行,则什么都不做;如果只有1行,检查F是0还是1,并插入一行与另一个值;如果两行都不存在,请同时插入它们。这需要为每个mtwlg完成,并且还需要插入唯一ID。
伪代码:
For each market type wager limit group ID
Check if there are 2 rows with that id in the stake distributions table, 1 where column X = 0 and one where column X = 1
if none
create 2 rows in the stake distributions table with unique id's; 1 for each X value
if one
create the missing row in the stake distributions table with a unique id
if 2
do nothing
如果它有帮助 - 将使用liquibase应用补丁。
对于是否以及如何使用SQL / liquibase补丁进行编写有任何建议或想法的人?
在此先感谢您,请告诉我您需要的任何其他信息。
编辑:
我实际上只是被建议使用PL / SQL做到这一点,您对此有什么想法/建议吗? 再次感谢。
答案 0 :(得分:4)
Oooooh,MERGE
的出色工作。
这是你的伪代码:
For each market type wager limit group ID
Check if there are 2 rows with that id in the stake distributions table,
1 where column X = 0 and one where column X = 1
if none
create 2 rows in the stake distributions table with unique id's;
1 for each X value
if one
create the missing row in the stake distributions table with a unique id
if 2
do nothing
以下是MERGE
变体(仍为伪代码,因为我不知道您的数据的真实外观):
MERGE INTO stake_distributions d
USING (
SELECT limit_group_id, 0 AS x
FROM market_type_wagers
UNION ALL
SELECT limit_group_id, 1 AS x
FROM market_type_wagers
) t
ON (
d.limit_group_id = t.limit_group_id AND d.x = t.x
)
WHEN NOT MATCHED THEN INSERT (d.limit_group_id, d.x)
VALUES (t.limit_group_id, t.x);
没有循环,没有PL / SQL,没有条件语句,只是简单漂亮的SQL。
Boneist在评论中提出的不错的替代方法是在CROSS JOIN
子句中使用UNION ALL
而不是USING
,可能执行更好(未经证实):
MERGE INTO stake_distributions d
USING (
SELECT w.limit_group_id, x.x
FROM market_type_wagers w
CROSS JOIN (
SELECT 0 AS x FROM DUAL
UNION ALL
SELECT 1 AS x FROM DUAL
) x
) t
ON (
d.limit_group_id = t.limit_group_id AND d.x = t.x
)
WHEN NOT MATCHED THEN INSERT (d.limit_group_id, d.x)
VALUES (t.limit_group_id, t.x);
答案 1 :(得分:2)
答案:你没有。绝对没有必要循环任何东西 - 你可以在一个插入中完成。您需要做的就是识别缺失的行,然后您只需要添加它们。
以下是一个例子:
drop table t1;
drop table t2;
drop sequence t2_seq;
create table t1 (cola number,
colb number,
colc number);
create table t2 (id number,
cola number,
colb number,
colc number,
colx number);
create sequence t2_seq
START WITH 1
INCREMENT BY 1
MAXVALUE 99999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
insert into t1 values (1, 10, 100);
insert into t2 values (t2_seq.nextval, 1, 10, 100, 0);
insert into t2 values (t2_seq.nextval, 1, 10, 100, 1);
insert into t1 values (2, 20, 200);
insert into t2 values (t2_seq.nextval, 2, 20, 200, 0);
insert into t1 values (3, 30, 300);
insert into t2 values (t2_seq.nextval, 3, 30, 300, 1);
insert into t1 values (4, 40, 400);
commit;
insert into t2 (id, cola, colb, colc, colx)
with dummy as (select 1 id from dual union all
select 0 id from dual)
select t2_seq.nextval,
t1.cola,
t1.colb,
t1.colc,
d.id
from t1
cross join dummy d
left outer join t2 on (t2.cola = t1.cola and d.id = t2.colx)
where t2.id is null;
commit;
select * from t2
order by t2.cola;
ID COLA COLB COLC COLX
---------- ---------- ---------- ---------- ----------
1 1 10 100 0
2 1 10 100 1
3 2 20 200 0
5 2 20 200 1
7 3 30 300 0
4 3 30 300 1
6 4 40 400 0
8 4 40 400 1
答案 2 :(得分:0)
如果处理逻辑太粗糙而无法封装在单个SQL语句中,则可能需要求助于循环和行类型的游标 - 基本上允许您执行以下操作:
DECLARE
r_mtwlg markettypewagerlimitgroups%ROWTYPE;
BEGIN
FOR r_mtwlg IN (
SELECT mtwlg.*
FROM markettypewagerlimitgroups mtwlg
)
LOOP
-- do stuff here
-- refer to elements of the current row like this
DBMS_OUTPUT.PUT_LINE(r_mtwlg.id);
END LOOP;
END;
/
你可以显然在这个触及stakedistributionindicators
表的那个循环中嵌套另一个循环,但是我将把它作为练习留给你。您也可以在第一个游标中多次连接到stakedistributionindicators
,这样您只返回那些还没有x = 1和x = 0的行,同样你也可以自己解决这个问题。
答案 3 :(得分:0)
如果您希望在Java与PL / SQL中编写逻辑,Liquibase允许您创建custom changes。自定义更改指向您编写的Java类,可以执行您需要的任何逻辑。可以找到一个简单的例子here