2009-07-05 3 views
1

저는이 문제를 여러 번 보았습니다. 문제를 해결하는 더 좋은 방법을 찾고 싶습니다.SQL 부모가 아닌 행을 null 값으로 가져 오기

기본적으로 하위 카테고리가있는 카테고리가 있습니다. 하위 범주에 설명이 없으면 상위 범주 설명을 검색하고 싶습니다.

서브 서브 카테고리가있을 때 어려워지기 시작합니다.

는 SQL 표는 다음과 같습니다

CategoryID   int, 
ParentCategoryID int null, 
Name    varchar(255), 
Description  varchar(MAX) null 

내가 설명을 보일 것이다 함수를 작성하고 싶습니다,하지만 난 그게 최선의 해결책이나 방법 함수를 만드는 방법인지 알 수 없습니다.

저는이 문제를 해결하기위한 최선의 방법을 찾고 있습니다.

+0

어떤 SQL 브랜드를 사용하고 있습니까? – Talljoe

+1

아마도 varchar (MAX) 구문에서 SQLServer처럼 보입니까? – Plasmer

+0

MsSql, 미안 그 표가 어떻게 생겼는지에 대한 의사 코드 일뿐입니다. 누구나이 기능을 사용하기 위해 함수를 사용할 수 있다고 생각합니까? 나는 '함께'물건을 좋아한다. MySql에 '함께'있습니까? –

답변

0

분명히 두 개의 테이블 참조와 조인이 필요합니다. 이렇게하면 두 설명에 모두 액세스 할 수 있습니다. 그런 다음 첫 번째 null에 따라 사용할 값을 선택하려면 inline if 문이 필요합니다. 이 같은

뭔가 당신의 구조를 감안할 때 (테이블 표라는)

SELECT Table1.CategoryID, IIf(Parent.Description Is Null, Table1.description, parent.description) AS [Desc] 
FROM Table1 INNER JOIN Table1 AS Parent ON Table1.CategoryID = Parent.ParentCategoryID; 
+0

계층 구조가 두 단계 인 경우에만 작동하지 않습니까? 또한 IF() 대신 COALESCE()를 사용할 수도 있습니다 –

+0

예, 2 단계 솔루션입니다. 그것이 내가이 질문을 읽는 방법이다. 위의 모든 레벨을 선택해야하지만 테스트하지는 않았습니다. –

+0

그 위의 어떤 레벨을 선택해야한다는 것을 어떻게 알 수 있습니까? –

1

작동합니다, 알렉스 마르 텔리의 솔루션은 아마 당신이 찾을 수있는 가장 좋습니다. 또 다른 옵션은 모델을 변경할 수있는 경우 연결된 목록 트리 구조에서 중첩 된 집합 모델로 변경하는 것입니다.

Joe Celko는 다양한 방법으로 모델을 만들 수 있으며 각 방법의 장단점을 설명합니다. a book on trees and hierarchies Google 또는 Google 그룹스를 통해 주제에 관한 많은 정보를 찾을 수도 있습니다.

중첩 세트 모델의 단점 중 하나는 트리 구조의 변경이 조금 비싸지 만 제품의 경우 일반적으로 업데이트하는 것보다 훨씬 많은 것을 검색한다는 것입니다. 특히 대부분의 비즈니스 사례에서 일반적으로 발생하지 않는 카테고리 사이를 이동합니다. 중첩 된 세트 모델을 사용

, 다음은 당신이 원하는 걸 줄 것이다 :

SELECT 
    P1.Name, 
    COALESCE(P1.Description, P2.Description) AS Description 
FROM 
    Products P1 
LEFT OUTER JOIN Products P2 ON 
    P2.lft < P1.lft AND 
    P2.rgt > P1.rgt AND 
    P2.Description IS NOT NULL 
LEFT OUTER JOIN Products P3 ON 
    P3.lft < P1.lft AND P3.lft > P2.lft AND 
    P3.rgt > P1.rgt AND P3.rgt < P2.rgt AND 
    P3.Description IS NOT NULL 
WHERE 
    P3.ID IS NULL 
3

가정 :

  1. 카테고리 ID는 기본 키입니다.

  2. 행 수준의 설명이 null 인 경우 상위 행을 살펴보십시오. 부모 행에 null 설명이 있으면 부모의 부모를 봅니다. 다른 말로하면 조상에 대한 첫 번째 null이 아닌 설명을 사용합니다. 로우 레벨 정보가 널 및 조상 비 널 묘사 없으면

  3. 은 전반적인 설명

설정 예에 나타난 테스트 데이터 널.

create table #SO (CategoryID int primary key 
    , ParentCategoryID int Null 
    , Name varchar(255) not null 
    , Description varchar(MAX) Null 
    ) 

insert into #SO (CategoryID, ParentCategoryID, Name, Description) 
values (1, null, 'Top 1', 'Top 1 Description') 
    , (2, null, 'Top 2', 'Top 2 Description') 
    , (3, null, 'Top 3', null) 
    , (11, 1, 'Child 11', 'Child 11 Description') 
    , (12, 1, 'Child 12', null) 
    , (21, 2, 'Child 21', null) 
    , (211, 21, 'Child 211', null) 
    , (2111, 211, 'Child 2111', null) 
    , (2112, 211, 'Child 2112', 'Child 2112 Description') 
    , (31, 3, 'Child 31', 'Child 31 Description') 
    , (32, 3, 'Child 32', null) 

재귀 CTE를 사용합니다. 트리는 위쪽으로 걸어갔습니다.우리는 모든 행부터 시작한 다음 나무 꼭대기에서 시작하여 아래로 작업하는 일반적인 트리 조작 대신에 필요에 따라 부모를 봅니다.

; with Description (BaseCategoryId 
     , CurrentParentCategoryId 
    , CurrentDescription 
    , CurrentLevel) 
    as 
(-- Anchor -- Start with all rows in the table. 
select CategoryId as BaseCategoryId 
    , ParentCategoryId as CurrentParentCategoryId 
    , Description as CurrentDescription 
    , 0 as CurrentLevel 
from #SO -- Recursive -- We are walking up the tree from all nodes, 
    -- We only continue up the tree when we do not have a description yet. 
union all 
select D.BaseCategoryId 
    , so.ParentCategoryId 
    , so.Description 
    , D.CurrentLevel + 1 
from #SO so 
inner join Description D 
    on D.CurrentParentCategoryId = so.CategoryId 
    and D.CurrentDescription is null) 
select DL.BaseCategoryId as CategoryId 
    , DL.CurrentDescription as UltimateDescription 
-- Now self outer join with the CTE every step of the walk 
-- for each BaseCategoryId, and then filter all but the top 
-- level. (Level is measured as distance from base.) 
from Description as DL 
left outer join Description as DR 
on DL.BaseCategoryId = DR.BaseCategoryId 
and DL.CurrentLevel < DR.CurrentLevel 
where DR.BaseCategoryId is null 
order by DL.BaseCategoryId 

출력은 CategoryId에서 최종 설명까지의 매핑입니다.

재사용 관점에서 볼 때 위와 같은 것을 볼 수 있습니다.

+0

100 이상의 재귀 수준이 있어야 SQL Server에서 CTE를 중지 할 때까지 정상적으로 작동합니다. 그러나 대부분의 경우 사람들은 많은 수준이나 데이터가 드문 드문 다루고 있습니다. 불행히도, 나는 운 좋은 소수 중 하나입니다. :) –

1

부모 트리를 재귀 적으로 처리해야하는 경우 answer from Alex을 참조하십시오. 한 레벨 만 필요하면 간단한 LEFT JOIN이 작동해야합니다.

SELECT  c.CategoryID, 
      c.ParentCategoryID, 
      c.Name, 
      COALESCE(c.Description, p.Description) AS Description 
FROM  dbo.Category c 
LEFT JOIN dbo.Category p 
     ON c.ParentCategoryID = p.CategoryID 
관련 문제