복붙노트

[SQL] 그것은 다른 아이에 의해 참조되어 있지 않은 경우 삭제 부모

SQL

그것은 다른 아이에 의해 참조되어 있지 않은 경우 삭제 부모

나는 예를 들어 상황을 가지고 : 부모 테이블은 외래 키로 자식 테이블에서 참조 ID라는 이름의 열이 있습니다.

자식 행을 삭제할 때이 다른 아이에 의해 참조 아니에요 아니라 것처럼, 어떻게 부모를 삭제하려면?

해결법

  1. ==============================

    1.PostgreSQL을 9.1 이상에서는 당신은 데이터 수정 CTE를 사용하여 하나의 문이 작업을 수행 할 수 있습니다. 이것은 일반적으로 더 적은 오류가 발생하기 쉬운입니다. 그것은 경쟁 조건이 동시 작업과 결과를 놀라게으로 이어질 수있는 두 건의 DELETE 사이의 시간 프레임을 최소화 :

    PostgreSQL을 9.1 이상에서는 당신은 데이터 수정 CTE를 사용하여 하나의 문이 작업을 수행 할 수 있습니다. 이것은 일반적으로 더 적은 오류가 발생하기 쉬운입니다. 그것은 경쟁 조건이 동시 작업과 결과를 놀라게으로 이어질 수있는 두 건의 DELETE 사이의 시간 프레임을 최소화 :

    WITH del_child AS (
        DELETE FROM child
        WHERE  child_id = 1
        RETURNING parent_id, child_id
        )
    DELETE FROM parent p
    USING  del_child x
    WHERE  p.parent_id = x.parent_id
    AND    NOT EXISTS (
       SELECT 1
       FROM   child c
       WHERE  c.parent_id = x.parent_id
       AND    c.child_id <> x.child_id   -- !
       );
    

    SQL 바이올린.

    아이는 어떤 경우 삭제됩니다. 나는 설명서를 인용 :

    그것은 다른 아이가없는 경우, 부모는 삭제됩니다. 마지막 조건을합니다. 사람이 기대하는 것과는 달리,이 때문에 필요하다 :

    굵게 강조 광산. 나는 비 설명 ID 대신에 열 이름 PARENT_ID을 사용했다.

    나는 완전히 위에서 언급 한 가능한 경쟁 조건을 제거하려면 먼저 부모 행을 잠급니다. 물론, 모든 유사한 작업은 작업하기 위해 같은 절차를 따라야합니다.

    WITH lock_parent AS (
       SELECT p.parent_id, c.child_id
       FROM   child  c
       JOIN   parent p ON p.parent_id = c.parent_id
       WHERE  c.child_id = 12              -- provide child_id here once
       FOR    NO KEY UPDATE                -- locks parent row.
       )
     , del_child AS (
       DELETE FROM child c
       USING  lock_parent l
       WHERE  c.child_id = l.child_id
       )
    DELETE FROM parent p
    USING  lock_parent l
    WHERE  p.parent_id = l.parent_id
    AND    NOT EXISTS (
       SELECT 1
       FROM   child c
       WHERE  c.parent_id = l.parent_id
       AND    c.child_id <> l.child_id   -- !
       );
    

    한 번에 하나의 트랜잭션이 방법은 같은 부모를 잠글 수 있습니다. 그것은 그 여러 트랜잭션에게 같은 부모의 삭제 아이가 발생하지 수, 여전히 다른 아이들을보고 모든 아이들이 나중에 갔다하는 동안, 부모를 아끼지. (키가 아닌 컬럼에 대한 업데이트는 여전히위한 NO KEY UPDATE로 사용할 수 있습니다.)

    이러한 경우가 발생하지 않습니다 또는 당신이 (좀처럼) 그것으로 살 수있는 경우 발생 - 첫 번째 쿼리가 저렴합니다. 그 밖에,이 보안 경로입니다.

    FOR NO KEY UPDATE는 포스트 그레스 9.4에서 도입되었습니다. 매뉴얼의 세부 사항. 이전 버전에서 대신 업데이트에 대한 강한 잠금을 사용합니다.

  2. ==============================

    2.

    delete from child
    where parent_id = 1
    

    아이 삭제 후 부모에 그것을 할 :

    delete from parent
    where
        id = 1
        and not exists (
            select 1 from child where parent_id = 1
        )
    

    되지는 조건이이 아이에 존재하지 않는 경우에만 삭제됩니다 있는지 확인합니다 존재한다. 당신은 트랜잭션을 모두 삭제 명령을 포장 할 수 있습니다 :

    begin;
    first_delete;
    second_delete;
    commit;
    
  3. from https://stackoverflow.com/questions/15809463/delete-parent-if-its-not-referenced-by-any-other-child by cc-by-sa and MIT license