it-swarm.com.de

Oracle: Wie wird eingefügt, wenn eine Zeile nicht existiert?

Was ist der einfachste Weg, eine Zeile in PL/SQL (Oracle) einzufügen, wenn sie nicht existiert?

Ich möchte etwas wie:

IF NOT EXISTS (SELECT * FROM table WHERE name = 'jonny') THEN
  INSERT INTO table VALUES ("jonny", null);
END IF;

Aber es funktioniert nicht.

Hinweis: Diese Tabelle hat zwei Felder, z. B. Name und Alter . Aber nur name ist PK.

43
Topera
INSERT INTO table
SELECT 'jonny', NULL
  FROM dual -- Not Oracle? No need for dual, drop that line
 WHERE NOT EXISTS (SELECT NULL -- canonical way, but you can select
                               -- anything as EXISTS only checks existence
                     FROM table
                    WHERE name = 'jonny'
                  )
63
Benoit

Vorausgesetzt, Sie haben 10g, können Sie auch die MERGE-Anweisung verwenden. Auf diese Weise können Sie die Zeile einfügen, wenn sie nicht vorhanden ist, und die Zeile ignorieren, wenn sie existiert. Die Leute neigen dazu, an MERGE zu denken, wenn sie einen "Aufwärtstrend" durchführen wollen (INSERT, wenn die Zeile nicht existiert, und UPDATE, falls die Zeile existiert), aber der UPDATE-Teil ist jetzt optional, sodass er hier auch verwendet werden kann.

SQL> create table foo (
  2    name varchar2(10) primary key,
  3    age  number
  4  );

Table created.

SQL> ed
Wrote file afiedt.buf

  1  merge into foo a
  2    using (select 'johnny' name, null age from dual) b
  3       on (a.name = b.name)
  4   when not matched then
  5    insert( name, age)
  6*    values( b.name, b.age)
SQL> /

1 row merged.

SQL> /

0 rows merged.

SQL> select * from foo;

NAME              AGE
---------- ----------
johnny
31
Justin Cave

Wenn name eine PK ist, fügen Sie einfach den Fehler ein. Der Grund dafür ist, dass keine Überprüfung durchgeführt wird, da mehrere Clients gleichzeitig einfügen. Wenn Sie prüfen und dann einfügen, müssen Sie während dieser Zeit eine Sperre halten oder den Fehler trotzdem erwarten.

Der Code dafür wäre ungefähr so

BEGIN
  INSERT INTO table( name, age )
    VALUES( 'johnny', null );
EXCEPTION
  WHEN dup_val_on_index
  THEN
    NULL; -- Intentionally ignore duplicates
END;
14
Lou Franco

Ich benutze Teile von @benoit answer und verwende Folgendes:

DECLARE
    varTmp NUMBER:=0;
BEGIN
    -- checks
    SELECT nvl((SELECT 1 FROM table WHERE name = 'john'), 0) INTO varTmp FROM dual;

    -- insert
    IF (varTmp = 1) THEN
        INSERT INTO table (john, null)
    END IF;

END;

Sorry, ich verwende keine vollständige Antwort, aber ich brauche IF, weil mein Code viel komplexer ist als diese Beispieltabelle mit den Feldern name und age. Ich brauche einen sehr klaren Code. Vielen Dank, ich habe viel gelernt! Ich akzeptiere die Antwort von @benoit.

9
Topera

Ich fand die Beispiele etwas schwierig zu befolgen für die Situation, in der Sie sicherstellen möchten, dass eine Zeile in der Zieltabelle vorhanden ist (insbesondere wenn Sie zwei Spalten als Primärschlüssel haben). Der Primärschlüssel ist jedoch möglicherweise überhaupt nicht vorhanden auswählen.

Das hat bei mir funktioniert:

MERGE INTO table1 D
    USING (
        -- These are the row(s) you want to insert.
        SELECT 
        'val1' AS FIELD_A,
        'val2' AS FIELD_B
        FROM DUAL

    ) S ON (
        -- This is the criteria to find the above row(s) in the
        -- destination table.  S refers to the rows in the SELECT
        -- statement above, D refers to the destination table.
        D.FIELD_A = S.FIELD_A
        AND D.FIELD_B = S.FIELD_B
    )

    -- This is the INSERT statement to run for each row that
    -- doesn't exist in the destination table.
    WHEN NOT MATCHED THEN INSERT (
        FIELD_A,
        FIELD_B,
        FIELD_C
    ) VALUES (
        S.FIELD_A,
        S.FIELD_B,
        'val3'
    )

Die wichtigsten Punkte sind:

  • Die SELECT-Anweisung im USING-Block muss immer Zeilen zurückgeben. Wenn von dieser Abfrage keine Zeilen zurückgegeben werden, werden keine Zeilen eingefügt oder aktualisiert. Hier wähle ich aus DUAL, so dass es immer genau eine Zeile gibt.
  • Die ON-Bedingung legt die Kriterien für das Übereinstimmen von Zeilen fest. Wenn ON keine Übereinstimmung hat, wird die INSERT-Anweisung ausgeführt.
  • Sie können auch eine WHEN MATCHED THEN UPDATE-Klausel hinzufügen, wenn Sie auch mehr Kontrolle über die Aktualisierungen haben möchten.
7
Malvineous

Zusätzlich zu den bisher gegebenen perfekten und gültigen Antworten gibt es auch den ignore_row_on_dupkey_index-Hinweis, den Sie verwenden möchten:

create table tq84_a (
  name varchar2 (20) primary key,
  age  number
);

insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Johnny',   77);
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Pete'  ,   28);
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Sue'   ,   35);
insert /*+ ignore_row_on_dupkey_index(tq84_a(name)) */ into tq84_a values ('Johnny', null);

select * from tq84_a;

Der Hinweis ist auf Tahiti beschrieben.

3

Sie können diese Syntax verwenden:

INSERT INTO table_name ( name, age )
select  'jonny', 18 from dual
where not exists(select 1 from table_name where name = 'jonny');

wenn es ein Popup für die Abfrage als "Substitutionsvariable eingeben" ist, verwenden Sie dies vor den obigen Abfragen: 

set define off;
INSERT INTO table_name ( name, age )
select  'jonny', 18 from dual
where not exists(select 1 from table_name where name = 'jonny');
1
user2667653

CTEund nurCTE:-)

wirf einfach extra Sachen raus.Hier ist eine fast vollständige und wortreiche Form für alle Fälle des Lebens. Und Sie können jedes kurze Formular verwenden.

INSERT INTO reports r
  (r.id, r.name, r.key, r.param)

-

  -- Invoke this script from "WITH" to the end (";")
  -- to debug and see prepared values.
  WITH

  -- Some new data to add.
  newData AS(
          SELECT 'Name 1' name, 'key_new_1' key FROM DUAL
    UNION SELECT 'Name 2' NAME, 'key_new_2' key FROM DUAL
    UNION SELECT 'Name 3' NAME, 'key_new_3' key FROM DUAL
    ),
  -- Any single row for copying with each new row from "newData",
  -- if you will of course.
  copyData AS(
      SELECT r.*
      FROM reports r
      WHERE r.key = 'key_existing'
        -- ! Prevent more than one row to return.
        AND FALSE -- do something here for than!
    ),
  -- Last used ID from the "reports" table (it depends on your case).
  -- (not going to work with concurrent transactions)
  maxId AS (SELECT MAX(id) AS id FROM reports),

-

  -- Some construction of all data for insertion.
  SELECT maxId.id + ROWNUM, newData.name, newData.key, copyData.param
  FROM copyData
    -- matrix multiplication :)
    -- (or a recursion if you're imperative coder)
    CROSS JOIN newData
    CROSS JOIN maxId

-

  -- Let's prevent re-insertion.
  WHERE NOT EXISTS (
      SELECT 1 FROM reports rs
      WHERE rs.name IN(
        SELECT name FROM newData
      ));

Ich nenne es " IF NOT EXISTS " für Steroide. Das hilft mir und ich mache das meistens.

0
it3xl