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 ALLlikely 表现更好(未验证):

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