테이블 삭제 관한 질문입니다. 1 13 2,933

by 지후 [MySQL] [2015.09.02 15:14:12]


ID CODE_NUM ITEM_NAME
215   과자
216   음료수
217   견과류
218 217 아몬드
219 217 땅콩
220 217 호두
221 219 오징어땅콩
222 219 계피맛땅콩
223 221 작은봉지
224 221 큰봉지

테이블 삭제 관련 하여 질문 드립니다. 하루종일 해매다 글 남겨 놓네요 ㅠ0ㅠ;
테이블 구조는 위와같습니다.
테이블 이름: ITEM_LIST

견과류
 - 땅콩
    - 계피맛땅콩
    - 오징어땅콩
       - 작은봉지
       - 큰봉지
  - 아몬드
  - 호두
이와 같은 형태 인데
견과류를 삭제하면 자동으로 아래 하위 목록까지 테이블에서 다 삭제 하고 싶습니다.

원하는 결과값

ID CODE_NUM ITEM_NAME
215   과자
216   음료수

이부분 명령어를 어떻게 해야 될까요?ㅠ0ㅠ 고수님들의 답변 부탁드립니다.

견과류 ID를 가지고 있는 아이템을 찾아내고 삭제하고 삭제된 셀에 ID를 가지고 있는 셀을 검색해서 또 삭제하고
다시 삭제된 셀에 ID를 갖고 있는 셀을 찾아내서 삭제하고... 이런식으로 반복해서 삭제하면 될것 같긴한데 잘 모르겠습니다.

위 테이블명를 토대로 예를 들어 쿼리문을 알려주시면 정말 감사하겠습니다.

by 아발란체 [2015.09.02 16:04:10]
--CONNECT_BY_ROOT를 이용하면 됩니다.

WITH T(id, code_num, item_name) AS (
  SELECT 215, NULL, '과자' FROM DUAL
  UNION ALL SELECT 216, NULL, '음료수' FROM DUAL
  UNION ALL SELECT 217, NULL, '견과류' FROM DUAL
  UNION ALL SELECT 218, 217, '아몬드' FROM DUAL
  UNION ALL SELECT 219, 217, '땅콩' FROM DUAL
  UNION ALL SELECT 220, 217, '호두' FROM DUAL
  UNION ALL SELECT 221, 219, '오징어땅콩' FROM DUAL
  UNION ALL SELECT 222, 219, '계피맛땅콩' FROM DUAL
  UNION ALL SELECT 223, 221, '작은봉지' FROM DUAL
  UNION ALL SELECT 224, 221, '큰봉지' FROM DUAL
  UNION ALL SELECT 227, 224, '밀폐형' FROM DUAL
)
SELECT
  id,
  code_num,
  LPAD(' ', LEVEL, ' ')||item_name,
  CONNECT_BY_ROOT id AS rid
FROM
  T
START WITH
  code_num IS NULL  
CONNECT BY
  PRIOR id = code_num

 

--위 결과를 이용하여 견과류 키 값 217 하위 다 삭제 처리

DELETE FROM [TABLE_NAME] WHERE id IN(
  SELECT 
    id
  FROM (
    SELECT
      id,
      code_num,
      LPAD(' ', LEVEL, ' ')||item_name,
      CONNECT_BY_ROOT id AS rid
    FROM
      T
    START WITH
      code_num IS NULL  
    CONNECT BY
      PRIOR id = code_num
  ) WHERE 
    rid = 217  
) 

 


by 지후 [2015.09.02 16:10:09]

최상위 부모 하나만 삭제시
하위 자식들까지 자동으로 삭제되게 할 수는 없나요?
추후 자식들과 부모가 어떤것들이 들어갈지 몇개의 갯수가 들어갈지 모르는데
이렇게 하게 되면 일일이 다 넣어줘야하지않나요?


by 아발란체 [2015.09.02 16:26:26]

말씀하신거 구현된 것입니다.

 

자식수 관계 없이, 자식의 자식이 있어도,

"rid = 217"의 rid 부분에 삭제할 최상위 부모 값 1개만 넣어주면 이하 자식들 다 삭제 됩니다.

1대가 아닌 자식의 자식까지 삭제되는 구조입니다.

 

계층형 쿼리의 CONNECT_BY_ROOT 라는 것을 참고하시면 이해하시는데 도움이 될 것 같습니다.


by 지후 [2015.09.02 16:37:54]
DELETE FROM ITEM_LIST WHERE ID IN(
  SELECT
    ID
  FROM (
    SELECT
      ID,
      CODE_NUM,
      LPAD(' ', LEVEL, ' ')||ITEM_NAME,
      CONNECT_BY_ROOT ID AS rid
    FROM
      T
    START WITH
      CODE_NUM IS NULL 
    CONNECT BY
      PRIOR ID= CODE_NUM
  ) WHERE
    rid = 217  
)

답변 정말 감사합니다. 지금 활용해 볼려고..
이렇게 217에 관한 애들을 삭제하라고 명령을 주었는데 쿼리문 오류가 납니다. ㅠ0ㅠ
어떤것이 잘못된 것일까요?

 


by 아발란체 [2015.09.02 16:39:52]

억.. ㅡ_ㅡ;; MySQL이군요. 죄송합니다. ㅠㅠ 죽을죄를.

SQL 다시 짜서 드릴께요...

MySQL이 계층형 쿼리 ㅡㅡ; 실력이 딸려 안습인데, 프로시저로 짜서 드릴께요. 잠시만요.


by 마농 [2015.09.02 16:38:48]

Connect By 계층 쿼리는 Oracle 전용입니다.


by 아발란체 [2015.09.02 16:41:36]

말씀 감사합니다. ㅠ_ㅠ 말씀 안주셨으면.. 오류 찾을려고 했습니다.


by 아발란체 [2015.09.02 17:35:25]

ㅠ_ㅠ;; MySQL 오랫만에 했더니, 정신 없네요.

일단 1depth 처리하는 프로시저랑 사용 예 드립니다.

필요하시다면, 1depth 이상도 삭제 되는 프로시저로 수정해서 드리겠습니다.

일단 프로시저는 아래 스크립트 복사해서 생성하시면 됩니다.

 

CREATE PROCEDURE PRC_DELETE_CHILD(
  super_parent_id INT,
  table_name VARCHAR(100),
  id_field_name VARCHAR(20),
  parent_id_field_name VARCHAR(20)
)
BEGIN
  SET @cnt = 0;
  SET @query = CONCAT("SELECT COUNT(*) INTO @cnt FROM ", table_name, " WHERE ", parent_id_field_name, " = ", super_parent_id);
  SELECT CONCAT('EXECUTE SQL : ', @query);
  PREPARE stmt FROM @query;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
  SELECT @cnt;
  
  IF @cnt != '0' THEN
    SET @query = CONCAT("DELETE FROM ", table_name, " WHERE ", parent_id_field_name, " = ", super_parent_id);
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
    
    SET @query = CONCAT("DELETE FROM ", table_name, " WHERE ", id_field_name, " = ", super_parent_id);
    PREPARE stmt FROM @query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
  END IF;

END;

 


by 아발란체 [2015.09.02 17:37:33]

실행은

CALL PRC_DELETE_CHILD(217, '테이블명', 'code_num', 'id');

 

여기서 217은 최상위 부모 id 값이며, 테이블명은 입력하셔야 하고,

code_num은 부모 id 값 필드명이고,

id는 부모 필드명입니다.


by 지후 [2015.09.02 17:42:54]

이렇게까지 답변해주셔서 너무 감사드립니다.

1 depth 이상이 될수도 있고 아닐수도 있는 상황이라 ㅠ0ㅠ;
참 어렵네요..
단순히 아까처럼 DELETE 문을 이용해서 삭제되면 좋은데 말이죠.
아직 초보라 이것저것 모르는게 많아 여기서 많이 도움이 되네요.
답변 다시한번 감사드리고요. 좀 더 찾아보겠습니다.


by 마농 [2015.09.02 17:50:16]

MySQL 프로시져를 안해봐서...직접 작성은 못하겠고...
자기 자신의 프로시져를 다시 호출하는 게 가능하다면? (오라클은 가능함)
재귀 호출방식의 삭제 프로시져를 만드시면 간단할 듯 하네요.
아래는 오라클 재귀 호출 프로시져 예시입니다.
 

CREATE OR REPLACE PROCEDURE p_delete(v_id NUMBER)
IS
BEGIN
    DELETE FROM t WHERE id = v_id;
    FOR c IN (SELECT id FROM t WHERE code_num = v_id)
    LOOP
        p_delete(c.id);
    END LOOP;
END;
/

 


by 아발란체 [2015.09.02 18:02:37]

와 많이 간단하네용. 오라클에서도 해봐야겠네용 ~ 감사합니다~ !


by 지후 [2015.09.02 18:03:10]

마농님 답변도 감사드립니다.

매번 좋은 답변 해주시네요.

아직 더 공부해야될것이 많은가 봅니다.

그나저나 해결을 해야되는데 ㅠ0ㅠ 큰일입니다.

Mysql 이나 Mssql

원쿼리로 가능한 방법이 없을가요?
 

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입