【问题标题】:Insert into Oracle SQL or Update if value already exist?如果值已经存在,则插入 Oracle SQL 或更新?
【发布时间】:2016-07-08 08:07:12
【问题描述】:

我想要的是:If key exist in Oracle SQL Table → UPDATE, otherwise do a INSERT

昨天玩了一整天后,我设法得到了 INSERT 部分(下面的查询),我现在需要的是 UPDATE 部分。

这就是我需要它的原因:我有一个 RadGridView(使用 Telerik 和 WPF)。当用户单击“插入”按钮时,将添加一个新行,并且在用户按 Enter 后,该值将插入到数据库中。但是用户也可以单击 RadGridView 中的可用行并更新值,因此我也需要更新数据库中的值(而不是执行 INSERT)。这就是为什么我想要一个可以执行 Udate 或 Insert 的查询。

感谢任何帮助,如果您有更好的方法来实现 INSERT 部分,我想知道它:)

我正在使用 Oracle SQL Developer (Windows 10)。

ps.我尝试了一些在 StackOverflow 上找到的解决方案,但无法将这些解决方案应用于我的问题。

表 1

+-----------------------------------+------------+--------+
|               ID                  |  ORIGTERM  |  CODE  |
+-----------------------------------+------------+--------+
| 126478                            | Grass      |  TEST  |
| 374628                            | Flower     |  TEST  |
| 128754                            | Tree       |  TEST  |
+-----------------------------------+------------+--------+

表2

+-----------------------------------+------------+---------+
|               ID                  |REPLACETERM |SYSCTLANG|
+-----------------------------------+------------+---------+
| 126478                            | Gras       |     3   |
| 374628                            | Blume      |     3   |
| 128754                            | Baum       |     3   |
+-----------------------------------+------------+---------+


我设法得到 INSERT 查询,它看起来像这样(例如插入单词“Plant”):

INSERT ALL 
   INTO Table1(origterm,code) VALUES (s_origterm,s_code) 
   INTO Table2(replaceterm) VALUES (s_replaceterm) 
  SELECT s_origterm, s_code, s_replaceterm 
    FROM (SELECT 'Plant' s_origterm, 'TEST' s_code, 'Pflanze' s_replaceterm FROM dual) 
    dual;

我还必须更新 Table2 的 ID 使其与 Table1 中的 ID 相同:

UPDATE Table2 SET Table2.ID = (SELECT Table1.ID FROM Table1 WHERE origterm='Plant') 
              WHERE replaceterm='Pflanze';

现在我有一个如下所示的表格:

    +-----------------------------------+------------+--------------+------+
    |               ID                  |  ORIGTERM  |  REPLACETERM | CODE |
    +-----------------------------------+------------+--------------+------+
    | 126478                            | Grass      |  Gras        | TEST |
    | 374628                            | Flower     |  Blume       | TEST |
    | 128754                            | Tree       |  Baum        | TEST |
    | 100000                            | Plant      |  Pflanze     | TEST |
    +-----------------------------------+------------+--------------+------+

SELECT g.ID, origterm, replaceterm, code FROM Table1 g, Table2 ct WHERE g.ID = ct.ID;

【问题讨论】:

  • 使用MERGE语句怎么样?
  • @psur 你能告诉我怎么做吗?如何将其应用于我的问题?
  • 为什么这两个表:table1 & table2 是分开的? ID 列是这两个表之一中的主键吗?为什么要使用这样的数据模型?第三张桌子 (ID, ORIGTERM, REPLACETERM, CODE) - table3 是什么?你如何获得id=100000 值?它来自一个序列吗?请说明您需要更新哪个表,以及新数据来自哪里,因为我迷路了。
  • @kordirko Table1 保存未翻译的术语,Table2 保存已翻译的术语。这样的数据模型是给我的。第三个Table是Table1和Table2的组合(看最后隐藏的SQL查询)。 ID 是主键。当我在 TABLE1 中插入 ORIGTERM 值时,将为我自动设置 ID,换句话说,我不需要添加 ID。我需要更新第三个表,但这是通过表 1 和表 2 完成的。

标签: c# sql oracle


【解决方案1】:

合并不适用于 INSERT ALL。如果你想使用合并,你应该从两个表中创建一个view with instead of trigger,而不是对视图使用合并。整个逻辑将在触发器内部。

编辑:合并不适用于此类视图 ORA-38106: MERGE bei Join View oder View mit INSTEAD OF-Trigger nicht unterstützt

您可以创建两个合并语句(每个表一个)或一个用于插入,一个用于更新视图:

CREATE SEQUENCE MYDICT_SEQ START WITH 1 MAXVALUE 9999999999999999999999999999 MINVALUE 0;

CREATE VIEW mydict
AS
   SELECT a.id, a.origterm, a.code, b.replaceterm, b.sysctlang
     FROM table1 a LEFT OUTER JOIN table2 b ON a.id = b.id;   

CREATE OR REPLACE TRIGGER mydict_io
   INSTEAD OF INSERT OR UPDATE OR DELETE
   ON mydict
   FOR EACH ROW
DECLARE
   cnt1   INTEGER := 0;
   cnt2   INTEGER;
   nid    NUMBER;
BEGIN
   IF INSERTING OR UPDATING THEN
      IF :new.id IS NULL AND INSERTING THEN
         nid := mydict_seq.NEXTVAL;
      ELSE
         nid := :new.id;

         IF UPDATING THEN
            nid := :old.id;
         END IF;

         SELECT COUNT (*)
           INTO cnt1
           FROM table1
          WHERE id = nid;
      END IF;

      IF cnt1 = 0 THEN
         INSERT INTO TABLE1 (ID, ORIGTERM, CODE)
              VALUES (nID, :new.ORIGTERM, :new.CODE);
      ELSIF cnt1 > 0 THEN
         UPDATE TABLE1
            SET ORIGTERM = :NEW.ORIGTERM, CODE = :NEW.CODE
          WHERE id = nid;
      END IF;

      SELECT COUNT (*)
        INTO cnt2
        FROM table2
       WHERE id = nid AND SYSCTLANG = :new.SYSCTLANG;

      IF cnt2 = 0 THEN
         INSERT INTO TABLE2 (ID, REPLACETERM, SYSCTLANG)
              VALUES (nID, :new.REPLACETERM, :new.SYSCTLANG);
      ELSE
         UPDATE TABLE2
            SET REPLACETERM = :new.REPLACETERM
          WHERE id = nid AND SYSCTLANG = :new.SYSCTLANG;
      END IF;
   ELSIF DELETING THEN
      DELETE FROM table2
            WHERE id = :old.id AND SYSCTLANG = :old.SYSCTLANG;

      SELECT COUNT (*)
        INTO cnt2
        FROM table2
       WHERE id = nid;

      IF cnt2 = 0 THEN
         DELETE FROM table1
               WHERE id = :old.id;
      END IF;
   END IF;
END;

DECLARE
   nid   NUMBER;
BEGIN
   INSERT INTO mydict (ORIGTERM, CODE, REPLACETERM, SYSCTLANG)
        VALUES ('Plant', 'TEST', 'Pflanze', 3);
    nid := mydict_seq.currval;


   UPDATE mydict
      SET REPLACETERM = 'Fabrik'
    WHERE id = nid;

   UPDATE mydict
      SET REPLACETERM = 'Usine', SYSCTLANG = 4
    WHERE id = nid;
END;

instead of trigger 中的逻辑可以做得更好,但我把这个留给你;)

【讨论】:

  • 哇,我得测试一下,但它太大了。希望有更小的东西。无论如何我会测试它并回来报告。
  • @Devid 视图的优点是可以直接绑定到RadGridView作为DataTable,不用关心插入、删除、更新语句
【解决方案2】:

也许这太明显了,但如果你拥有'key'值,这个过程可能会起作用:

DECLARE _flag AS INT = 0;

SELECT COUNT() INTO _flag FROM table1 WHERE ID = key;

IF _flag = 0 THEN
   INSERT ...
ELSE
   UPDATE ....
END IF;

根据您自己的代码需求和/或 ORACLE SQL 方言进行调整。

【讨论】:

  • 我对 SQL 的理解不是很先进,你能解释一下你的代码吗? DECLARE _flag AS INT = 0 是什么意思?做吗?
  • 声明一个 INT 类型的变量 _flag 和默认值 0...正确的语法可能会在 SQL 方言之间发生变化,但我很确定它应该可以工作.. 如果您愿意,可以将其一分为二行.... DECLARE _flag AS INT; SET _flag = 0;
  • 在某些 SQL 方言中可以省略 'AS'
【解决方案3】:

一种可能的解决方案是使用 MERGE 关键字,此处记录:

http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9016.htm

Merge 基本上是一个“upsert”命令,这意味着如果存在则更新行,如果不存在则插入。

【讨论】:

  • 我看到了 MERGE 命令,但问题是当我想将它应用于我的问题时,我总是遇到错误。我犯了一些错误。如果您能告诉我如何将合并应用于我的问题,我会将您的答案标记为解决方案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多