Oracle SQL - 如何编写有条件且循环的插入语句?
Oracle SQL - How can I write an insert statement that is conditional and looped?
上下文:
我有两个 table:markettypewagerlimitgroups (mtwlg) 和 stakedistributionindicators (sdi)。创建 mtwlg 时,在链接到 mtwlg 的 sdi table 中创建 2 行 - 每行具有相同的值 bar 2,id 和另一个字段(我们称之为 X 列)必须包含一个一行为 0,另一行为 1。
我们的代码库中存在一个错误,它阻止了这种情况的自动发生,因此在存在错误期间创建的任何 mtwlg 都没有相关的 sdi,从而导致在各个地方出现 NPE。
要解决这个问题,需要编写一个补丁来循环遍历 mtwlg table 并针对每个 ID 在 sdi table 中搜索 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/a liquibase 补丁的建议或想法吗?
提前致谢,如果您需要任何其他信息,请告诉我。
编辑:
实际上我刚刚被建议使用 PL/SQL 执行此操作,你有任何关于此的 thoughts/suggestions 吗?
再次感谢。
如果处理逻辑太粗糙而无法封装在单个 SQL 语句中,您可能需要求助于游标 for 循环和行类型 - 基本上允许您执行以下操作:
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
table,但我会把它留给您作为练习。您还可以在第一个游标中多次离开 stakedistributionindicators
的连接,这样您就只有 return 行还没有 x=1 和 x=0,您也可以这样做为自己加油。
太棒了 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。
在评论中建议的不错的替代方案在 USING
子句中使用 CROSS JOIN
而不是 UNION ALL
,likely 表现更好(未验证):
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);
答案:你不知道。绝对不需要遍历任何东西——你可以在一个插入中完成。您需要做的就是找出缺失的行,然后您只需添加它们即可。
这是一个例子:
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
如果您更愿意在 Java 中编写您的逻辑而不是 PL/SQL,Liquibase 允许您创建 custom changes. The custom change points to a Java class you write that can do whatever logic you need. A simple example can be found here
上下文: 我有两个 table:markettypewagerlimitgroups (mtwlg) 和 stakedistributionindicators (sdi)。创建 mtwlg 时,在链接到 mtwlg 的 sdi table 中创建 2 行 - 每行具有相同的值 bar 2,id 和另一个字段(我们称之为 X 列)必须包含一个一行为 0,另一行为 1。 我们的代码库中存在一个错误,它阻止了这种情况的自动发生,因此在存在错误期间创建的任何 mtwlg 都没有相关的 sdi,从而导致在各个地方出现 NPE。
要解决这个问题,需要编写一个补丁来循环遍历 mtwlg table 并针对每个 ID 在 sdi table 中搜索 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/a liquibase 补丁的建议或想法吗?
提前致谢,如果您需要任何其他信息,请告诉我。
编辑:
实际上我刚刚被建议使用 PL/SQL 执行此操作,你有任何关于此的 thoughts/suggestions 吗? 再次感谢。
如果处理逻辑太粗糙而无法封装在单个 SQL 语句中,您可能需要求助于游标 for 循环和行类型 - 基本上允许您执行以下操作:
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
table,但我会把它留给您作为练习。您还可以在第一个游标中多次离开 stakedistributionindicators
的连接,这样您就只有 return 行还没有 x=1 和 x=0,您也可以这样做为自己加油。
太棒了 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。
USING
子句中使用 CROSS JOIN
而不是 UNION ALL
,likely 表现更好(未验证):
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);
答案:你不知道。绝对不需要遍历任何东西——你可以在一个插入中完成。您需要做的就是找出缺失的行,然后您只需添加它们即可。
这是一个例子:
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
如果您更愿意在 Java 中编写您的逻辑而不是 PL/SQL,Liquibase 允许您创建 custom changes. The custom change points to a Java class you write that can do whatever logic you need. A simple example can be found here