source

MySQL에서 재귀 SELECT 쿼리를 수행하는 방법

gigabyte 2022. 9. 5. 23:08
반응형

MySQL에서 재귀 SELECT 쿼리를 수행하는 방법

다음 테이블이 있습니다.

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

가 "은 "1"을 .col1"가진 "1"의 .col3라고 하면 은 '5'에서를 계속 합니다.col1 '3'에서 '이 나옵니다.col3출력할 수중에 있습니다.

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

유저가 「6」을 검색하면, 다음의 출력이 됩니다.

6   | o   | 2
2   | 0   | 8

★★★★의 방법SELECT문할할 수???

편집

@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 FIDDLE Demo

다음 쿼리를 사용해 보십시오.

SELECT 
    col1, col2, @pv := col3 as 'col3' 
FROM 
    table1
JOIN 
    (SELECT @pv := 1) tmp
WHERE 
    col1 = @pv

다음과 같습니다SQL FIDDLE Demo.

| COL1 | COL2 | COL3 |
+------+------+------+
|    1 |    a |    5 |
|    5 |    d |    3 |
|    3 |    k |    7 |

★★★
parent_id 값은 이보다 .child_id이 솔루션이 작동하도록 합니다.

@Meherzad에 의해 받아들여진 답변은 데이터가 특정 순서로 되어 있는 경우에만 기능합니다.OP 질문의 데이터로 동작합니다.제 경우 데이터를 사용하기 위해 수정해야 했습니다.

이것은 모든 레코드의 "id"(질문의 col1)가 해당 레코드의 "parent 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

점은 '하다'는 것입니다.table1하고 있습니다.col1 위해서의 「부모」는 「부모」의 「col1을 이용하다)

좌클릭벤의 답변은 효과가 있었지만, 저는 주어진 노드에서 루트로 돌아가는 경로를 원했습니다.이것들은 반대 방향으로 가고 있는 것 같았습니다. 트리 아래로요.그래서 몇 개의 필드를 뒤집고 이름을 바꿨어요. 그리고 이건 저에게도 효과가 있어요. 만약 다른 사람들도 이걸 원할지도 모르니까요.

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

저장 프로시저가 가장 좋은 방법입니다.왜냐하면 메헤르자드의 솔루션은 데이터가 동일한 순서를 따를 경우에만 작동하기 때문입니다.

이런 테이블 구조를 가지고 있다면

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

효과가 없을 것이다.SQL Fiddle Demo

다음은 동일한 작업을 수행하기 위한 샘플 절차 코드입니다.

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;

부모 ID가 자녀 ID보다 낮아야 하는 문제 없이 SELECT를 사용할 수 있도록 하려면 함수를 사용할 수 있습니다.또, 복수의 아이(트리가 필요한 경우)를 서포트해, 트리는 복수의 헤드를 가질 수 있습니다.또한 데이터에 루프가 존재하는 경우에도 중단됩니다.

테이블/컬럼 이름을 전달하기 위해 동적 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$$

기기 、 이 here 。test이치노ParentId,Id를 사용하다

사용방법:

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

편집: 여기 직접 테스트할 수 있는 바이올린이 있습니다.미리 정의된 딜리미터를 사용하여 딜리미터를 변경할 수 밖에 없었습니다만, 정상적으로 동작합니다.

마스터 DJon을 기반으로 구축

다음은 깊이 반환의 추가 유틸리티를 제공하는 단순화된 함수입니다(특정 깊이에서 상위 작업 또는 검색을 포함하기 위해 논리를 사용하는 경우).

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;

언급URL : https://stackoverflow.com/questions/16513418/how-to-do-the-recursive-select-query-in-mysql

반응형