使用"如果不存在"在程序中

时间:2014-03-20 18:50:25

标签: sql plsql

我正在尝试创建一个过程,如果尚未使用该ID,则会向我插入新条目。我只是无法弄清楚我在那里做的事情:

CREATE OR REPLACE PROCEDURE add_user
IS
BEGIN
    IF NOT EXISTS SELECT * FROM tab WHERE tab.id = '111'
    THEN
INSERT INTO tab(id, name, job, city, phone)
        VALUES(111, 'Frank', 'Programmer', 'Chicago', '111111111');
END IF;
END;

3 个答案:

答案 0 :(得分:3)

您问题的直接答案是将子查询放在括号中:

IF NOT EXISTS (SELECT * FROM tab WHERE tab.id = 111) THEN
    INSERT INTO tab(id, name, job, city, phone)
        VALUES(111, 'Frank', 'Programmer', 'Chicago', '111111111');
END IF;

但是,这不是解决问题的好方法(我删除了单引号,因为常量在一个地方引用但在另一个地方没引用)。一个问题是竞争条件。 not exists部分可能会运行,然后另一个进程可能会插入该行,然后insert将失败。

正确的解决方案是:

create unique index tab_id on tab(id);

然后,对merge使用insert。或者将insert包装在异常处理代码中。 ,使用日志工具:

    INSERT INTO tab(id, name, job, city, phone)
        VALUES(111, 'Frank', 'Programmer', 'Chicago', '111111111');
    LOG ERRORS INTO errlog ('Oops, something went wrong') REJECT LIMIT UNLIMITED;

然后您将不会允许将重复的行插入表中。他们不会进去,你不会得到错误(除非你想要一个)。

答案 1 :(得分:2)

不要试图在代码中强制执行引用完整性,因为它非常非常可能非常非常错误。显然不是 错误 - 不,这就是"错误"只有当你有200个用户敲打数据库然后出现在非常匆忙的南方时才会出现,突然间没有人可以使用系统或做他们的工作而你的手机响了,你的老板正在呼吸蒸汽和灰烬落在你的脖子后面,你的汗水和你的触点上的汗水流淌,你无法看到,你无法思考,而且......你知道,那种有点不对劲。 : - )

相反,请使用旨在阻止此类错误的数据库的引用完整性功能。一个好的起点是关于规范化的规则。你还记得,你在学校里了解过他们,并且每个人都说他们是多么粗鲁,而且为什么我们必须学习这个垃圾,因为每个人知道 没人做这件事,因为它不重要,是吧,哈哈,哈哈,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈是的,那些东西 - 几天之后的一些项目,比如上面的段落你突然得到宗教信息,因为它会拯救你(更聪明你,年长但更聪明的你)和你愚蠢的屁股,就像上面那段日子一样。

首先,确保您的表具有主键。鉴于上面的字段名称,我建议它应该是ID列。要创建此约束,请在SQL * Plus命令行中发出以下命令:

ALTER TABLE TAB ADD CONSTRAINT TAB_PK PRIMARY KEY(ID);

现在,将您的程序重写为

CREATE OR REPLACE PROCEDURE add_user IS
BEGIN
  INSERT INTO TAB
    (id, name, job, city, phone)
  VALUES
    (111, 'Frank', 'Programmer', 'Chicago', '111111111');
EXCEPTION
  WHEN DUP_VAL_ON_INDEX THEN
    EXIT;  -- fine - the user already exists
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error in ADD_USER : ' || SQLCODE || ' : ' || SQLERRM);
    RAISE;
END;

所以,不要试图预先检查海岸是否清晰,我们只是插入并插入该死的用户!因为我们是程序员!我们很强!!我们不关心潜在的风险!我们喝含有高果味玉米糖浆的含咖啡因的软饮料!错误不能吓到我们!!!

我们不是男士?!?!?

嗯,实际上,如果我们负责(而不是#34;应该受到谴责的程序员),我们实际上只关心潜在的错误,如果只是因为我们知道他们会降落在我们的办公桌上,很可能是因为我们宁愿在网上冲浪,也不是在学习新的编程语言,或者在下一个工作过程中与女孩聊天/流口水营销和谁严重脱离我们的联盟 - 我的观点是,错误关注我们。避免它们,正确处理它们 - 这些都是专业开发人员与dweeb崇拜者和管理前锋的区别。这使我们在INSERT语句之后立即进入代码行:

<强>异常

那是对的 - 我们知道INSERT声明可能会出错 - 但是因为我们男人,而我们负责程序员,我们将做正确的事情,在这种情况下意味着&#34;处理我们可以预见的例外情况&#34;。我们该怎么办?

WHEN DUP_VAL_ON_INDEX THEN

GREAT!我们知道我们可以获得DUP_VAL_ON_INDEX异常,因为当我们尝试插入已经存在的用户时会发生什么。然后我们做正确的事:

  EXIT;  -- fine - the user already exists.

在这种情况下,完全忽略错误。不完全是!我们正在尝试插入新用户。我们尝试插入的用户已经在那里。什么不爱?现在,很可能在那个神秘,神话般的地方叫做“真实世界”,它可能被认为是简单地忽略这个事实,并且可能需要做一些事情,例如记录事实,有人试图添加一个已经存在的用户 - 但是在PretendLand中,我们只是说,很好 - 用户已经存在,所以我们很高兴。

但是等等 - 更多!不仅仅是我们要处理(并且,是的,好的,忽略)DUP_VAL_ON_INDEX异常,我们还将处理任何其他可能的错误条件,以便人类或数据库类型!

WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') ||
                       '  Error in ADD_USER : ' || SQLCODE || ' : ' || SQLERRM);
  RAISE;

这意味着我们会吐出一个有用的错误消息告诉使用WHEN,WHERE和WHAT出错,然后重新引发异常(无论它可能是什么),以便任何人打电话给我们让它毫无顾忌地倾倒进入他们的膝盖,所以他们可以处理它。 (服务给我们的权利,懒惰的某某人......)。

所以,现在你知道了。

去做你的好事。

并且......分享并享受。

答案 2 :(得分:1)

您忘记在IF语句中添加()

  CREATE OR REPLACE PROCEDURE add_user
    IS
    BEGIN
        IF NOT EXISTS (SELECT * FROM tab WHERE tab.id = '111') THEN
    INSERT INTO tab(id, name, job, city, phone)
            VALUES(111, 'Frank', 'Programmer', 'Chicago', '111111111');
    END IF;
    END;