it-source

Oracle: 행이 없는 경우 삽입하는 방법

criticalcode 2023. 3. 2. 22:19
반응형

Oracle: 행이 없는 경우 삽입하는 방법

PL/SQL(oracle)에서 행이 없는 경우 가장 쉽게 삽입할 수 있는 방법은 무엇입니까?

나는 다음과 같은 것을 원한다.

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

근데 안 되네.

주의: 이 표에는 이름과 기간이라는 두 개의 필드가 있습니다.하지만 이름만 PK야.

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'
                  )

10g을 사용하는 경우 MERGE 문을 사용할 수도 있습니다.그러면 행이 없으면 삽입하고 행이 있으면 무시할 수 있습니다.사람들은 "업서트"(행이 없으면 삽입하고 행이 있으면 업데이트)를 수행할 때 MERGE를 떠올리는 경향이 있지만, UPDATE 부분은 현재 옵션이기 때문에 여기서도 사용할 수 있습니다.

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

이름이 PK인 경우 오류를 삽입하고 파악합니다.체크가 아닌 이 작업을 하는 이유는 여러 클라이언트를 동시에 삽입해도 작동하기 때문입니다.체크 후 삽입할 경우 해당 시간 동안 잠금을 유지하거나 오류를 예상해야 합니다.

이 암호는 다음과 같습니다.

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

행이 행선지 테이블에 존재하는 것을 확인하고 싶은 경우(특히 프라이머리 키로 2개의 열이 있는 경우)에는, 이 예에서는, 행이 행선지 테이블에 존재하지 않는 경우가 있기 때문에, 선택할 필요가 없는 경우가 있습니다.

이것이 나에게 효과가 있었다.

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'
    )

요점은 다음과 같습니다.

  • SELECT안에 있는 성명USING블록은 항상 행을 반환해야 합니다.이 쿼리에서 반환된 행이 없으면 행이 삽입되거나 업데이트되지 않습니다.여기서 선택합니다.DUAL그래서 항상 한 줄만 있을 거예요.
  • ONcondition은 행을 일치시키기 위한 기준을 설정합니다.한다면ON일치하는 항목이 없으면 INSERT 문이 실행됩니다.
  • 추가 가능WHEN MATCHED THEN UPDATEclause를 참조해 주세요.

@benoit answer의 일부를 사용하여 다음을 사용합니다.

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;

제가 충분한 답변을 하지 못해서 죄송하지만,IF내 코드가 이름과 나이 필드가 있는 이 예제 표보다 훨씬 더 복잡하기 때문에 확인합니다.아주 명확한 암호가 필요해고마워, 나는 많은 것을 배웠어!@benoit 답변을 받아들이겠습니다.

지금까지 주어진 완벽하고 유효한 답변 외에ignore_row_on_dupkey_index사용할 수 있는 힌트:

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;

그 힌트는 타히티에서 묘사된다.

다음 구문을 사용할 수 있습니다.

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

"대체 변수 입력"을 묻는 팝을 연 경우 위의 쿼리 전에 이 팝을 사용하십시오.

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');

Merge를 사용해야 합니다.예를 들어 다음과 같습니다.

MERGE INTO employees e
    USING (SELECT * FROM hr_records WHERE start_date > ADD_MONTHS(SYSDATE, -1)) h
    ON (e.id = h.emp_id)
  WHEN MATCHED THEN
    UPDATE SET e.address = h.address
  WHEN NOT MATCHED THEN
    INSERT (id, address)
    VALUES (h.emp_id, h.address);

또는

MERGE INTO employees e
    USING hr_records h
    ON (e.id = h.emp_id)
  WHEN MATCHED THEN
    UPDATE SET e.address = h.address
  WHEN NOT MATCHED THEN
    INSERT (id, address)
    VALUES (h.emp_id, h.address);

https://oracle-base.com/articles/9i/merge-statement

CTE유일한 CTE :-)

그냥 여분의 물건을 버려라.여기 삶의 모든 경우에 대해 거의 완벽하고 장황한 형식이 있다.그리고 어떤 간결한 형식이라도 사용할 수 있습니다.

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
      ));

저는 스테로이드제를 "만약 존재하지 않는다면"이라고 부릅니다.그래서 이게 도움이 되고 저는 대부분 그렇게 해요.

언급URL : https://stackoverflow.com/questions/3841441/oracle-how-to-insert-if-a-row-doesnt-exist

반응형