Oracle SQL - 如何编写有条件和循环的insert语句?

时间:2015-05-14 09:07:30

标签: sql oracle sql-update conditional-statements liquibase

上下文: 我有两个表: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做到这一点,您对此有什么想法/建议吗? 再次感谢。

4 个答案:

答案 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