문제

내가 사용하여 중첩된 세트(aka 수정 전순 트리 순회)목록을 저장의 그룹,나를 찾으려고 빠른 방법을 생성하는 빵 부스러기(문자열로,지 테이블)의 모든 그룹이다.나의 데이터가 저장되어를 사용하여 인접 목록에 모델을(있을 유지하기 위해 트리거 동기화의 두).

그래서 예를 들어:

ID   Name    ParentId  Left   Right
0    Node A  0         1      12
1    Node B  0         2      5
2    Node C  1         3      4
3    Node D  0         6      11
4    Node E  3         7      8
5    Node F  4         9      9

를 나타내는 트리:

  • 노드
    • 노드 B
      • 노 C
    • 노드 D
      • 노드 E
      • 노 F

하고 싶을 가질 수 있는 사용자 정의 테이블을 반환하는 함수입니다:

ID  Breadcrumb
0   Node A
1   Node A > Node B
2   Node A > Node B > Node C
3   Node A > Node D
4   Node A > Node D > Node E
5   Node A > Node D > Node F

이것을 조금 더 복잡한(하지만 그것의 종류의 범위는 질문),나 또한 사용자 제한될 필요가 있는 존경합니다.그래서 예를 들어,경우에만 액세스 id=3 때,나는 실행하는 쿼리를 얻어야 한다:

ID  Breadcrumb
3   Node D
4   Node D > Node E
5   Node D > Node F

나는 사용자 정의 함수는 사용자 id 으로 매개 변수 테이블을 반환된 id 의 모든 그룹이 유효하므로 어딘가에서 쿼리

WHERE group.id IN (SELECT id FROM dbo.getUserGroups(@userid))

그것은 작동합니다.


기존에 스칼라 기능을 할 수 있는 것이지만,그것은 단지 작동하지 않는 모든 적절한 수의 그룹(걸리>10 초에는 2000 년 그룹).그것은 groupid 및 userid 매개변수로,그리고 반환하 이며.그것을 발견된 그룹 부모님(1 쿼리를 잡아하는 왼쪽/오른쪽의 값이고,다른 부모를 찾기 위해),목록이 제한됩니 그룹은 사용자가 액세스할 수 있는(를 사용하여 같은 곳에 절로서,위의 그래서 아직 다른 쿼리)을 사용하여 커서를 이동을 통해 각 그룹에 추가하여,문자열기 전에 마지막으로 반환하는 값입니다.

내가 필요로 하는 방법을 이렇게 하는 것이 신속하게 실행하는(예를 들어.<=1),니다.

이에 SQL Server2005.

도움이 되었습니까?

해결책 4

내가 한 일은 모든 수준에 따라이 테이블을 단순히 계속해서 묶는 큰 결합을 만드는 것입니다.

먼저 1 레벨 그룹만으로 테이블 @TopleVelGroups를 채 웁니다 (루트가 하나만있는 경우이 단계를 건너 뛸 수 있음), @UserGroups는 사용자가 볼 수있는 그룹과 함께 @USERGROUP을 채 웁니다.

SELECT groupid,
   (level1 
    + CASE WHEN level2 IS NOT NULL THEN ' > ' + level2 ELSE '' END
    + CASE WHEN level3 IS NOT NULL THEN ' > ' + level3 ELSE '' END
   )as [breadcrumb]
FROM (
  SELECT g3.*
    ,g1.name as level1
    ,g2.name as level2
    ,g3.name as level3
  FROM @topLevelGroups g1
  INNER JOIN @userGroups g2 ON g2.parentid = g1.groupid and g2.groupid <> g1.groupid
  INNER JOIN @userGroups g3 ON g3.parentid = g2.groupid 

  UNION

  SELECT g2.*
    ,g1.name as level1
    ,g2.name as level2
    ,NULL as level3
  FROM @topLevelGroups g1 
  INNER JOIN @userGroups g2 ON g2.parentid = g1.groupid and g2.groupid <> g1.groupid

  UNION

  SELECT g1.*
    ,g1.name as level1
    ,NULL as level2
    ,NULL as level3 
  FROM @topLevelGroups g1

) a
ORDER BY [breadcrumb]

이것은 꽤 큰 해킹이며, 특정 수준의 수준으로 제한되어 있습니다 (내 앱의 경우 선택할 수있는 합리적인 제한이 있습니다). 더 많은 레벨이 지원 될수록 기하 급수적으로 조인 수를 증가시키는 문제가 있습니다. 따라서 훨씬 느립니다.

코드로 수행하는 것이 가장 확실하지만 항상 옵션은 아닙니다. SQL 쿼리에서 직접 사용할 수있는 시간이 있습니다.


나는 이것을 대답으로 받아들이고 있습니다. 왜냐하면 그것이 내가 한 일이었고 다른 사람들에게는 효과가있을 수 있기 때문입니다. 그러나 누군가가 더 효율적인 방법을 생각해 낼 수 있다면 그들에게 그것을 바꿀 것입니다.

다른 팁

다음은 나무의 어느 지점에서나 "빵 부스러기"경로를 얻기 위해 일한 SQL입니다. 도움이되기를 바랍니다.

SELECT ancestor.id, ancestor.title, ancestor.alias 
FROM `categories` child, `categories` ancestor 
WHERE child.lft >= ancestor.lft AND child.lft <= ancestor.rgt 
AND child.id = MY_CURRENT_ID 
ORDER BY ancestor.lft

캐스

확인. 이것은 SQL Server 2005가 아닌 MySQL 용입니다. 하위 쿼리가있는 Group_Concat을 사용합니다.

이것은 전체 빵 부스러기를 단일 열로 반환해야합니다.

SELECT 
 (SELECT GROUP_CONCAT(parent.name SEPARATOR ' > ')
 FROM category parent
 WHERE node.Left >= parent.Left
 AND node.Right <= parent.Right
 ORDER BY Left
 ) as breadcrumb
FROM category node
ORDER BY Left

는 경우,당신이 할 수있는 경로를 사용하여(또는 생각이 들었어요 이라고 혈통)같은 분야:

ID   Name    ParentId  Left   Right   Path
0    Node A  0         1      12      0,
1    Node B  0         2      5       0,1,
2    Node C  1         3      4       0,1,2,
3    Node D  0         6      11      0,3,
4    Node E  3         7      8       0,3,4,
5    Node F  4         9      9       0,3,4,

을 얻을 노드 개발과 이후(psuedocode):

path = SELECT Path FROM Nodes WHERE ID = 3
SELECT * FROM Nodes WHERE Path LIKE = path + '%'

나는 모든 요소에 대한 빵 부스러기를 얻기 위해 Kathy의 진술을 수정했습니다.

SELECT
    GROUP_CONCAT(
        ancestor.name
        ORDER BY ancestor.lft ASC
        SEPARATOR ' > '
    ),
    child.*
FROM `categories` child
JOIN `categories` ancestor
ON child.lft >= ancestor.lft
AND child.lft <= ancestor.rgt
GROUP BY child.lft
ORDER BY child.lft

Where Condition을 자유롭게 추가하십시오

 WHERE ancestor.lft BETWEEN 6 AND 11

SQL Server 특정 코드는 없지만 단순히 다음을 찾고 있습니까?

왼쪽 <(currentId.left) 및 오른쪽> (currentID.right)에서 *를 선택하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top