2008-09-12 2 views
7

다음 표가 있습니다. groups 계층 적으로 정렬 된 그룹을 포함하는 테이블과 사용자가 속한 그룹을 저장하는 group_member.SQL 재귀

groups 
--------- 
id 
parent_id 
name 

group_member 
--------- 
id 
group_id 
user_id 

ID PARENT_ID NAME 
--------------------------- 
1 NULL  Cerebra 
2 1   CATS 
3 2   CATS 2.0 
4 1   Cerepedia 
5 4   Cerepedia 2.0 
6 1   CMS 

ID GROUP_ID USER_ID 
--------------------------- 
1 1  3 
2 1  4 
3 1  5 
4 2  7 
5 2  6 
6 4  6 
7 5  12 
8 4  9 
9 1  10 

주어진 사용자의 보이는 그룹을 검색하고 싶습니다. 그것은 사용자가 속한 그룹과이 그룹의 하위 그룹을 말합니다. 예를 들어, 위 데이터의 경우 :

USER VISIBLE_GROUPS 
9  4, 5 
3  1,2,4,5,6 
12 5 

이 값은 재귀 및 여러 데이터베이스 쿼리를 사용하여 얻게됩니다. 하지만 내 응용 프로그램 성능을 향상시키기 위해 단일 SQL 쿼리로이 작업을 수행 할 수 있는지 알고 싶습니다. MySQL을 사용하고 있습니다.

답변

0

난 당신이 내가이 재귀를 사용하지 않고 수행 할 수 있다고 생각하지 않습니다 이것에 대한 커서, this link

+0

codeproject 링크는 SQL Server 용으로 작성되었습니다. 이 코드를 mySQL에 적용하는 것은 쉽지 않을 수 있지만 여기에 커서에 대한 mySQL 참조가 있습니다. http://dev.mysql.com/doc/refman/5.0/en/cursors.html – Prestaul

0

도움이 될 필요 해요 생각합니다. mySQL을 사용하는 단일 저장 프로 시저로이 작업을 수행 할 수 있지만 기본적으로 저장 프로 시저에서는 재귀가 허용되지 않습니다. This article에는 재귀를 활성화하는 방법에 대한 정보가 있습니다. 나는 이것이 다중 쿼리 접근법에 비해 성능에 얼마나 많은 영향을 미치는지 확신 할 수 없다. mySQL은 저장 프로 시저의 최적화를 수행 할 수도 있지만 그렇지 않은 경우에는 성능이 비슷할 것으로 예상됩니다.

당신이 사용자 테이블이 있다면 가
0

알고하지 않았다, 그래서 나는 USER_ID 년대 Group_Member 테이블에 저장을 통해 목록을 가져가 ...

SELECT GroupUsers.User_ID, 
     (
     SELECT 
      STUFF((SELECT ',' + 
      Cast(Group_ID As Varchar(10)) 
      FROM Group_Member Member (nolock) 
      WHERE Member.User_ID=GroupUsers.User_ID 
     FOR XML PATH('')),1,1,'') 
     ) As Groups 
FROM (SELECT User_ID FROM Group_Member GROUP BY User_ID) GroupUsers 

반환 :

User_ID Groups 
3   1 
4   1 
5   1 
6   2,4 
7   2 
9   4 
10   1 
12   5 

이 보인다 당신의 테이블에있는 데이터에 따라 그러나 예상 값 목록과 일치하지 않습니다 (예 : 사용자 9는 테이블 데이터의 한 그룹에만 있지만 결과에 두 개의 그룹으로 표시됨)

EDIT : Dang. MySQL을 사용하고있는 것으로 나타났습니다. 내 솔루션은 SQL Server 용이었습니다. 죄송합니다.

- 케빈 페어차일드

-1

는 SQL 표준에서이 작업을 수행 할 수있는 방법은 없습니다,하지만 당신은 일반적으로 오라클에서, CONNECT BY을 예를 들어, 벤더 고유의 확장을 찾을 수 있습니다. 당신은 반복적으로 재귀 적으로 자신에게 표를 외부에 가입 할 수 있습니다 -

1 :

UPDATE : 코멘트 지적으로,이 SQL 99

+0

잘못되었습니다. ISO SQL 표준은 SQL : 1999 표준 이후로 재귀 SQL을 지정했습니다. DB2와 최신 버전의 MSSQL이이를 구현합니다. SQL 표준의 재귀 SQL은 Oracle의 CONNECT BY와 다소 다릅니다. –

+0

나는 그것을 몰랐다. ISO는 개발자가 표준 자체에 대해 비용을 지불해야한다고 생각하기 때문에 최신 표준에 대한 무료 참조가 있습니까? –

6

두 가지에 추가 된 마음에 와서 같이 당신의 나무를 걸어 :

SELECT * 
FROM 
    MY_GROUPS MG1 
,MY_GROUPS MG2 
,MY_GROUPS MG3 
,MY_GROUPS MG4 
,MY_GROUPS MG5 
,MY_GROUP_MEMBERS MGM 
WHERE MG1.PARENT_ID = MG2.UNIQID (+) 
    AND MG1.UNIQID = MGM.GROUP_ID (+) 
    AND MG2.PARENT_ID = MG3.UNIQID (+) 
    AND MG3.PARENT_ID = MG4.UNIQID (+) 
    AND MG4.PARENT_ID = MG5.UNIQID (+) 
    AND MGM.USER_ID = 9 

거 같은 당신에게 결과를 얻을 수있어 그 :

UNIQID PARENT_ID NAME  UNIQID_1 PARENT_ID_1 NAME_1 UNIQID_2 PARENT_ID_2 NAME_2 UNIQID_3 PARENT_ID_3 NAME_3 UNIQID_4 PARENT_ID_4 NAME_4 UNIQID_5 GROUP_ID USER_ID 
4  2   Cerepedia 2  1   CATS 1  null  Cerebra null  null  null null  null  null 8  4  9 

제한 사항은 트리를 걸어 갈 각 "수준"에 대해 새 조인을 추가해야한다는 것입니다. 나무의 레벨이 20 레벨보다 낮 으면 모든 사용자로부터 20 레벨을 보여주는보기를 만들어서 벗어날 수 있습니다.

2 - 내가 알고있는 유일한 접근 방식은 재귀 데이터베이스 함수를 만들고 코드에서 호출하는 것입니다. 그런 방식으로 쿼리가 계속 발생합니다 (즉, 쿼리의 수는 여전히 트리를 걷는 수준 수와 같음). 그러나 전반적으로 쿼리가 데이터베이스 내에서 발생하기 때문에 더 빨라야합니다.

MySql에 대해서는 잘 모르겠지만 오라클에서는 이러한 기능이 비슷할 것입니다 (테이블과 필드 이름을 변경해야하며 과거에했던 것을 복사하고 있습니다) :

CREATE OR REPLACE FUNCTION GoUpLevel(WO_ID INTEGER, UPLEVEL INTEGER) RETURN INTEGER 
IS 
BEGIN 
    DECLARE 
    iResult INTEGER; 
    iParent INTEGER; 
BEGIN 
    IF UPLEVEL <= 0 THEN 
    iResult := WO_ID; 
    ELSE 
    SELECT PARENT_ID 
    INTO iParent 
    FROM WOTREE 
    WHERE ID = WO_ID;  
    iResult := GoUpLevel(iParent,UPLEVEL-1); --recursive 
    END; 
    RETURN iResult; 
    EXCEPTION WHEN NO_DATA_FOUND THEN 
    RETURN NULL; 
    END; 
END GoUpLevel; 
/
3

조 Cleko의 책 "에 smarties에 대한 SQL에서 나무와 계층" "에 smarties에 대한 SQL"과 중첩 세트를 사용하여 완전히 재귀를 피할 방법을 설명합니다. 이는 업데이트를 복잡하게하지만 다른 쿼리 (일반적으로 재귀가 필요함)를 비교적 간단하게 만듭니다. Joe가 1996 년에 작성한 some examples in this article이 있습니다.

0

제기 된 것은 이미 question입니다.

여기 내 대답 (편집 비트)입니다 :

내가 제대로 질문을 이해 잘 모르겠지만,이 My take on trees in SQL를 작동 할 수있다.

링크 된 게시물은 데이터베이스에 트리를 저장하는 방법을 설명합니다 (이 경우 PostgreSQL). 그러나이 방법은 충분히 명확하므로 어떤 데이터베이스에도 쉽게 적용 할 수 있습니다.

이 방법을 사용하면 수정 된 노드 K에 의존하는 모든 노드를 N 간단한 SELECT 쿼리로 쉽게 업데이트 할 수 있습니다. 여기서 N은 루트 노드와 K 거리입니다.

행운을 빌어 요!

0

내가 링크를 찾은 사람이 누구인지 기억이 나지 않지만 this article on sitepoint.com (두 번째 페이지)은 계층 구조 트리를 테이블에 저장하여 모든 하위 노드 또는 상위 경로를 쉽게 찾을 수있는 다른 방법을 보여줍니다. , 그런 것들. 예제 코드로 좋은 설명.


추신. Newish to StackOverflow, 위의 확인은 대답입니까? 아니면 질문에 대한 주석이었을까요? 다른 솔루션에 대한 포인터 일 뿐이므로 (정확하게 질문 자체에 응답하지 않음)?