복붙노트

[SQL] 어떻게 MySQL의에서 재귀 SELECT 쿼리를 할까?

SQL

어떻게 MySQL의에서 재귀 SELECT 쿼리를 할까?

나는 다음과 같은 테이블을 가지고 :

col1 | col2 | col3
-----+------+-------
1    | a    | 5
5    | d    | 3
3    | k    | 7
6    | o    | 2
2    | 0    | 8

"1"에 대한 사용자 검색이 프로그램이 "1"인 COL1 볼 것이다 경우는, 다음 프로그램이 COL1에서 "5"를 검색 계속 COL3 "5"의 값을 얻을 것이다 그것을 얻을 것이다 "3"COL3에서, 등등. 이 인쇄됩니다 그래서 :

1   | a   | 5
5   | d   | 3
3   | k   | 7

"6"에 대한 사용자 검색, 그것은 인쇄됩니다 :

6   | o   | 2
2   | 0   | 8

어떻게 그렇게 할 수있는 SELECT 쿼리를 구축?

해결법

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

    1.편집하다

    편집하다

    @leftclickben 언급 해결 방법도 효과적이다. 우리는 또한 같은위한 저장 프로 시저를 사용할 수 있습니다.

    CREATE PROCEDURE get_tree(IN id int)
     BEGIN
     DECLARE child_id int;
     DECLARE prev_id int;
     SET prev_id = id;
     SET child_id=0;
     SELECT col3 into child_id 
     FROM table1 WHERE col1=id ;
     create TEMPORARY  table IF NOT EXISTS temp_table as (select * from table1 where 1=0);
     truncate table temp_table;
     WHILE child_id <> 0 DO
       insert into temp_table select * from table1 WHERE col1=prev_id;
       SET prev_id = child_id;
       SET child_id=0;
       SELECT col3 into child_id
       FROM TABLE1 WHERE col1=prev_id;
     END WHILE;
     select * from temp_table;
     END //
    

    우리는 출력의 결과를 저장하고 임시 테이블은 같은 세션을 기반으로 우리가 잘못 출력되는 데이터에 관한 문제가되지 않을 것 실 거예요 임시 테이블을 사용하고 있습니다.

    SQL 뿐인 데모 이 쿼리 검색 :

    SELECT 
        col1, col2, @pv := col3 as 'col3' 
    FROM 
        table1
    JOIN 
        (SELECT @pv := 1) tmp
    WHERE 
        col1 = @pv
    
    | COL1 | COL2 | COL3 |
    +------+------+------+
    |    1 |    a |    5 |
    |    5 |    d |    3 |
    |    3 |    k |    7 |
    

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

    2.데이터가 특정 순서에있는 경우 @Meherzad에 의해 허용 대답에만 작동합니다. 그것은 OP 질문의 데이터로 작업에 발생합니다. 내 경우, 나는 내 데이터와 함께 작동하도록 수정했다.

    데이터가 특정 순서에있는 경우 @Meherzad에 의해 허용 대답에만 작동합니다. 그것은 OP 질문의 데이터로 작업에 발생합니다. 내 경우, 나는 내 데이터와 함께 작동하도록 수정했다.

    (질문에서 COL1) 모든 레코드의 "ID가"보다 큰 값을 가지고이 비로소 작동을 참고 레코드의 "부모 ID가"(질문에 COL3). 일반적으로 부모가 처음 생성 될 필요가 있기 때문에, 종종 경우입니다. 응용 프로그램이 항목이 다시 부모가 다른 곳에서 할 수있는 계층 구조에 대한 변경을 허용하지만 경우에, 당신은 이것에 의존 할 수 없다.

    이것은 사람이 도움이 경우 내 쿼리입니다; 이 데이터가 필요한 구조는 위에서 설명한 주어진 질문 작업을 수행하지 않기 때문에주의.

    select t.col1, t.col2, @pv := t.col3 col3
    from (select * from table1 order by col1 desc) t
    join (select @pv := 1) tmp
    where t.col1 = @pv
    

    차이는 (부모 COL1 값은 어린이의보다 낮기 때문에) 이후에 부모가되도록 해당 표를 COL1으로 정렬되고있다.

  3. ==============================

    3.leftclickben 대답은 나를 위해 일한,하지만 난 루트에 나무까지 주어진 노드의 뒷면에서 경로를 원했고, 이러한 나무 아래, 다른 길을 갈 것 같았다. 그래서 나는 주변 일부 필드를 반전했다 및 명확성을 위해 이름을 변경하고, 나를 위해이 작품은, 경우에 이것은 다른 사람이 너무 ... 원하는 것입니다

    leftclickben 대답은 나를 위해 일한,하지만 난 루트에 나무까지 주어진 노드의 뒷면에서 경로를 원했고, 이러한 나무 아래, 다른 길을 갈 것 같았다. 그래서 나는 주변 일부 필드를 반전했다 및 명확성을 위해 이름을 변경하고, 나를 위해이 작품은, 경우에 이것은 다른 사람이 너무 ... 원하는 것입니다

    item | parent
    -------------
    1    | null
    2    | 1
    3    | 1
    4    | 2
    5    | 4
    6    | 3
    

    select t.item_id as item, @pv:=t.parent as parent
    from (select * from item_tree order by item_id desc) t
    join
    (select @pv:=6)tmp
    where t.item_id=@pv;
    

    제공 :

    item | parent
    -------------
    6    | 3
    3    | 1
    1    | null
    
  4. ==============================

    4.저장 프로 시저 그것을 할 수있는 가장 좋은 방법입니다. 데이터가 동일한 순서를 따릅니다 경우 Meherzad의 솔루션은 작동합니다 때문입니다.

    저장 프로 시저 그것을 할 수있는 가장 좋은 방법입니다. 데이터가 동일한 순서를 따릅니다 경우 Meherzad의 솔루션은 작동합니다 때문입니다.

    우리는이 같은 테이블 구조가있는 경우

    col1 | col2 | col3
    -----+------+------
     3   | k    | 7
     5   | d    | 3
     1   | a    | 5
     6   | o    | 2
     2   | 0    | 8
    

    그것은 작동 실 거예요. SQL 바이올린 데모

    여기서이를 달성하는 샘플 순서 코드이다.

    delimiter //
    CREATE PROCEDURE chainReaction 
    (
        in inputNo int
    ) 
    BEGIN 
        declare final_id int default NULL;
        SELECT col3 
        INTO final_id 
        FROM table1
        WHERE col1 = inputNo;
        IF( final_id is not null) THEN
            INSERT INTO results(SELECT col1, col2, col3 FROM table1 WHERE col1 = inputNo);
            CALL chainReaction(final_id);   
        end if;
    END//
    delimiter ;
    
    call chainReaction(1);
    SELECT * FROM results;
    DROP TABLE if exists results;
    
  5. ==============================

    5.당신이 자식 ID보다 낮은해야하는 부모 ID의 문제없이 선택을 할 수있게하려면, 함수가 사용될 수있다. 또한 여러 아이들을 지원 (나무가해야 할로)과 나무는 여러 개의 머리를 할 수 있습니다. 또한 루프가 데이터에있는 경우 휴식을 보장합니다.

    당신이 자식 ID보다 낮은해야하는 부모 ID의 문제없이 선택을 할 수있게하려면, 함수가 사용될 수있다. 또한 여러 아이들을 지원 (나무가해야 할로)과 나무는 여러 개의 머리를 할 수 있습니다. 또한 루프가 데이터에있는 경우 휴식을 보장합니다.

    나는 테이블 / 컬럼 이름을 통과 할 수 있도록 동적 SQL을 사용하고 싶어하지만, MySQL은 기능이 지원되지 않습니다.

    DELIMITER $$
    
    CREATE FUNCTION `isSubElement`(pParentId INT, pId INT) RETURNS int(11)
    DETERMINISTIC    
    READS SQL DATA
    BEGIN
    DECLARE isChild,curId,curParent,lastParent int;
    SET isChild = 0;
    SET curId = pId;
    SET curParent = -1;
    SET lastParent = -2;
    
    WHILE lastParent <> curParent AND curParent <> 0 AND curId <> -1 AND curParent <> pId AND isChild = 0 DO
        SET lastParent = curParent;
        SELECT ParentId from `test` where id=curId limit 1 into curParent;
    
        IF curParent = pParentId THEN
            SET isChild = 1;
        END IF;
        SET curId = curParent;
    END WHILE;
    
    RETURN isChild;
    END$$
    

    여기에 테이블 테스트는 당신의 진짜 이름을 조정해야 할 수있는 실제 테이블 이름과 열 (ParentId, 아이디)를 수정할 수 있습니다.

    사용법 :

    SET @wantedSubTreeId = 3;
    SELECT * FROM test WHERE isSubElement(@wantedSubTreeId,id) = 1 OR ID = @wantedSubTreeId;
    

    결과 :

    3   7   k
    5   3   d
    9   3   f
    1   5   a
    

    테스트 생성을위한 SQL :

    CREATE TABLE IF NOT EXISTS `test` (
      `Id` int(11) NOT NULL,
      `ParentId` int(11) DEFAULT NULL,
      `Name` varchar(300) NOT NULL,
      PRIMARY KEY (`Id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1;
    
    insert into test (id, parentid, name) values(3,7,'k');
    insert into test (id, parentid, name) values(5,3,'d');
    insert into test (id, parentid, name) values(9,3,'f');
    insert into test (id, parentid, name) values(1,5,'a');
    insert into test (id, parentid, name) values(6,2,'o');
    insert into test (id, parentid, name) values(2,8,'c');
    

    편집 : 여기에 스스로를 테스트 할 수있는 바이올린입니다. 그것은 미리 정의 된 하나를 사용하여 구분 기호를 변경하라고 강요하지만, 그것을 작동합니다.

  6. ==============================

    6.마스터 디종 오프 구축

    마스터 디종 오프 구축

    (상위 작업을 포함하거나 특정 깊이에서 검색 로직을 사용하려는 경우) 깊이를 반환하는 추가 유틸리티를 제공합니다 여기에 단순화 기능

    DELIMITER $$
    FUNCTION `childDepth`(pParentId INT, pId INT) RETURNS int(11)
        READS SQL DATA
        DETERMINISTIC
    BEGIN
    DECLARE depth,curId int;
    SET depth = 0;
    SET curId = pId;
    
    WHILE curId IS not null AND curId <> pParentId DO
        SELECT ParentId from test where id=curId limit 1 into curId;
        SET depth = depth + 1;
    END WHILE;
    
    IF curId IS NULL THEN
        set depth = -1;
    END IF;
    
    RETURN depth;
    END$$
    

    용법:

    select * from test where childDepth(1, id) <> -1;
    
  7. from https://stackoverflow.com/questions/16513418/how-to-do-the-recursive-select-query-in-mysql by cc-by-sa and MIT license