2013-04-28 3 views
6

계층 구조가있는 자산 데이터베이스에서 작업하고 있습니다. 또한 효과적으로 자산을 다시 가리키는 "ReferenceAsset"테이블이 있습니다. 참조 자산은 기본적으로 재정의로 기능하지만 고유 한 새 자산 인 것처럼 선택됩니다. 설정된 재정의 중 하나가 parent_id입니다.
자산 : 다음 계층 구조를 선택과 관련된SQL Server : 계층 적 및 참조 된 데이터 쿼리

열 ID (1 차),
자산 참조 PARENT_ID : 아이디 (주), ASSET_ID (foreignkey-> 자산), PARENT_ID (항상 자산)
를 - --EDITED 5/27 ----

시료와 관계있는 테이블 데이터 (결합 후)

id | asset_id | name   | parent_id | milestone | type 

    3  3  suit    null  march  shape 
    4  4  suit_banker   3   april  texture 
    5  5  tie    null  march  shape 
    6  6  tie_red    5   march  texture 
    7  7  tie_diamond   5   june  texture 
    -5  6  tie_red    4   march  texture 

id < 0 (마지막 행과 마찬가지로)은 참조되는 자산을 나타냅니다. 참조 된 저작물에는 몇 개의 열이 있지만이 경우에는 parent_id 만 중요합니다.

기대 내가 4 월부터 모든 자산을 선택하면, 내가 일치하는 쿼리의 전체 나뭇 가지를 얻을 수있는 보조 선택을해야한다는 것입니다 : 그래서 처음에 검색어 검색이 초래

을에서 :

4  4  suit_banker   3   april  texture 

그런 다음 CTE 후, 우리는 전체 계층 구조를 얻을이 (지금까지이 작동) 우리의 결과는

0이어야한다
3  3  suit    null  march  shape 
    4  4  suit_banker   3   april  texture 
    -5  6  tie_red    4   march  texture 

하고 참조 ID의 부모 : -5가있다,하지만없는 것은, 즉 필요, 참조 된 자산이며, 참조 된 자산의 부모 :

5  5  tie    null  march  shape 
    6  6  tie_red    5   march  texture 

현재 내 솔루션이 작동하지만 참조의 깊이가 하나만으로 제한됩니다. 구현이 상당히 엉망이라고 생각합니다.

--- 편집 됨 ---- 내 기본 선택 기능은 다음과 같습니다. 이것은 실제로 복잡한 문제가있는 곳을 잘 보여줍니다 : AssetReference.

Select A.id as id, A.id as asset_id, A.name,A.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name, B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID, 
M.name as milestoneName, A.deleted as bDeleted, 0 as reference, W.phase_name, W.status_name 
FROM Asset as A Inner Join Type as T on A.type_id = T.id 
Inner Join Batch as B on A.batch_id = B.id 
Left Join Location L on A.location_id = L.id 
Left Join Asset A2 on A.parent_id = A2.id 
Left Join AssetOwner AO on A.owner_id = AO.owner_id 
Left Join Milestone M on A.milestone_id = M.milestone_id 
Left Join Workflow as W on W.asset_id = A.id 
where A.deleted <= @showDeleted 

UNION 

Select -1*AR.id as id, AR.asset_id as asset_id, A.name, AR.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name, B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID, 
M.name as milestoneName, A.deleted as bDeleted, 1 as reference, NULL as phase_name, NULL as status_name 
FROM Asset as A Inner Join Type as T on A.type_id = T.id 
Inner Join Batch as B on A.batch_id = B.id 
Left Join Location L on A.location_id = L.id 
Left Join Asset A2 on AR.parent_id = A2.id 
Left Join AssetOwner AO on A.owner_id = AO.owner_id 
Left Join Milestone M on A.milestone_id = M.milestone_id 
Inner Join AssetReference AR on AR.asset_id = A.id 
where A.deleted <= @showDeleted 

임시 테이블 (#temp)을 사용하고 계층 구조의 모든 요소를 ​​찾는 저장 프로 시저가 있습니다.

  1. 는 #에서 (
  2. 쿼리와 일치하는 자산의 전체 계층 구조를 가져옵니다 임시 테이블에 전체 시스템의 계층 구조 각 전체 나무 가지의 쉼표로 구분 된 목록으로 표시 (#treeIDs)을 선택합니다 : 내가 사용 된 전략이 있었다 임시)
  3. 받기 모든 참조 자산 기준 자산은 항상 라이기 때문에 모든 참조 자산
  4. 이 지금은 작동

의 계층 구조를 구문 분석 계층 구조

  • 에서 자산 가리키는 st 항목에 있지만, 그렇지 않은 경우 문제가 될 것이라고 생각합니다. 나는 재귀의 좀 더 나은 형태가 필요하다고 느낀다.

    여기에 노력하고 내 현재 코드입니다,하지만 난 그것을 자랑하지 생각하고 (참조가 맨 아래에있는 경우에만 작동하기 때문에) 나는 그것이 강력한 아니라는 것을 알고 :

    1 단계. 쿼리를

    Select DISTINCT L.id into #RelativeIDs FROM #treeIDs 
    CROSS APPLY dbo.SplitIDs(idList) as L 
    WHERE #treeIDs.id in (Select id FROM #temp) 
    

    3 단계와 일치하는 모든 자산의 가지를 선택 전체 계층 구조

    ;WITH Recursive_CTE AS (
    SELECT Cast(id as varchar(100)) as Hierarchy, parent_id, id 
    FROM #assetIDs 
    Where parent_id is Null 
    
    UNION ALL 
    
    SELECT 
    CAST(parent.Hierarchy + ',' + CAST(t.id as varchar(100)) as varchar(100)) as Hierarchy, t.parent_id, t.id 
    FROM Recursive_CTE parent 
    INNER JOIN #assetIDs t ON t.parent_id = parent.id 
    ) 
    
    
    
    Select Distinct h.id, Hierarchy as idList into #treeIDs 
    FROM (Select Hierarchy, id FROM Recursive_CTE) parent 
    CROSS APPLY dbo.SplitIDs(Hierarchy) as h 
    

    2 단계를 구축 받기 모든 참조 자산 가지,536,913에서 63,210

    Select asset_id INTO #REFLinks FROM #AllAssets WHERE id in 
    (Select #AllAssets.asset_id FROM #AllAssets Inner Join #RelativeIDs 
    on #AllAssets.id = #RelativeIDs.id Where #RelativeIDs.id < 0) 
    

    4 단계 (참고 자산 따라서 ID < 0 부분, 부정적인 ID 값이) 아무것도의 가지가 난 그냥 보여 시도한 3

    Select DISTINCT L.id into #extraRelativeIDs FROM #treeIDs 
    CROSS APPLY dbo.SplitIDs(idList) as L 
    WHERE 
    exists (Select #REFLinks.asset_id FROM #REFLinks WHERE #REFLinks.asset_id = #treeIDs.id) 
    and Not Exists (select id FROM #RelativeIDs Where id = #treeIDs.id) 
    

    단계에서 발견하기 관련 코드. 나는 더 나은 해결책을 찾도록 도와 줄 수있는 누구에게나 고맙게 생각한다!

  • +0

    사용중인 sql 버전은 무엇입니까? http://msdn.microsoft.com/de-de/library/bb677290.aspx – NickD

    +0

    sql server 2012,하지만 방금 전환 했으므로 대부분이 2008 년 작성되었습니다 – haggercody

    답변

    1
    --getting all of the children of a root node (could be > 1) and it would require revising the query a bit 
    
    DECLARE @AssetID int = (select AssetId from Asset where AssetID is null); 
    
    
    --algorithm is relational recursion 
    --gets the top level in hierarchy we want. The hierarchy column 
    --will show the row's place in the hierarchy from this query only 
    --not in the overall reality of the row's place in the table 
    
    WITH Hierarchy(Asset_ID, AssetID, Levelcode, Asset_hierarchy) 
    AS 
    (
    SELECT AssetID, Asset_ID, 
         1 as levelcode, CAST(Assetid as varchar(max)) as Asset_hierarchy 
    FROM Asset 
    WHERE [email protected] 
    
    UNION ALL 
    
    --joins back to the CTE to recursively retrieve the rows 
    --note that treelevel is incremented on each iteration 
    
    SELECT A.Parent_ID, B.AssetID, 
         Levelcode + 1 as LevelCode, 
         A.assetID + '\' + cast(A.Asset_id as varchar(20)) as Asset_Hierarchy 
    FROM Asset AS a 
          INNER JOIN dbo.Batch AS Hierarchy 
          --use to get children, since the parentId of the child will be set the value 
          --of the current row 
          on a.assetId= b.assetID 
    --use to get parents, since the parent of the Asset_Hierarchy row will be the asset, 
          --not the parent. 
          on Asset.AssetId= Asset_Hierarchy.parentID 
    
    
    SELECT a.Assetid,a.name, 
         Asset_Hierarchy.LevelCode, Asset_Hierarchy.hierarchy 
    FROM  Asset AS a 
         INNER JOIN Asset_Hierarchy 
           ON A.AssetID= Asset_Hierarchy.AssetID 
    ORDER BY Hierarchy ; 
    --return results from the CTE, joining to the Asset data to get the asset name 
    ---that is the structure you will want. I would need a little more clarification of your table structure 
    
    +0

    와우. 훌륭한. 고맙습니다! – haggercody

    0

    기본 테이블 구조를 아는 것이 도움이됩니다. 환경에 따라 작동해야하는 두 가지 접근 방식이 있습니다. SQL은 XML을 이해하므로 SQL 구조를 XML로 사용하거나 고유 한 기본 키 ID와 상위 항목이있는 각 행 항목이있는 단일 테이블 만 가질 수 있습니다. id는 parentid에 대한 fk입니다. 노드의 데이터는 표준 열일뿐입니다. 계산 된 열에 전원을 공급하는 함수 나 함수를 사용하여 각 노드의 중첩 정도를 결정할 수 있습니다. 노드가 하나의 상위 노드 만 가질 수 있다는 한계가 있습니다.

    +0

    감사합니다.
    테이블 구조를 더 잘 보여주는 선택 기능으로 OP를 업데이트했습니다. 이 문제는 실제로 AssetReference 테이블 주위에 있습니다. 배치 모자로 자산 선택 : [BallCap] - 을 얻은 다음 [BallCap] (벌금까지)에 대한 전체 트리 분기를 선택합니다. 하지만 AssetReference가 다음과 같이 나타납니다. 트리 이제 참조 된 원래 자산을 선택해야합니다. 그리고이 자산에 대한 전체 트리가 필요합니다. – haggercody

    +0

    노드에 대한 분기 집합이 있고 해당 분기 중 하나에있는 노드가 될 수 있습니다 완전히 다른 나무 요? –

    +0

    예, 분기의 노드는 다른 트리 분기에있을 수있는 다른 노드를 '참조'할 수 있습니다. 이 '참조'는 다른 테이블 (AssetReference)에서 가져온 것입니다. 나는 여기서 설계 계명을 깨뜨린거야? – haggercody