2009-07-05 10 views
1

私はこの問題を数回見つけました。私はこの問題を解決するためのより良い方法を探したいと思います。SQL親の行から最初にNULL値を取得しない

基本的に私はサブカテゴリを持つカテゴリを持っています。サブカテゴリに説明がない場合は、親カテゴリの説明を取得したいと思います。

Sub Sub Categoriesがあると難しくなり始めます。

SQLの表は次のようになります。

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

私は説明をアップになります関数を作成したいと思いますが、それが最善の解決策や方法関数を作成するかどう私は考えています。

私は主にこの問題を解決するための最良の方法を探しています。

+0

使用しているSQLのブランドは? – Talljoe

+1

おそらくvarchar(MAX)の構文からSQLServerのように見えますか? – Plasmer

+0

MsSql、申し訳ありませんが、テーブルがどのように見えるのか疑似コードでした。 誰かがこれを達成するために関数を使用できると思いますか?私は「もの」のものが好きです。 MySqlには「with」がありますか? –

答えて

0

明らかに2つのテーブル参照と結合が必要です。これにより、両方の説明にアクセスできます。次に、最初にnullに基づいて、どの値を使用するかを選択するには、inline ifステートメントが必要です。あなたの構造を考えると、このような何かが動作するはず

(表を表1と命名された)

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

これは、階層が2つのレベルにしかない場合にのみ機能しますか?また、IF()の代わりにCOALESCE()を使用することもできます –

+0

はい、2段階の解決方法です。それが私がその質問を読む方法です。それはその上の任意のレベルを選ぶべきですが、私はそれをテストしていません。 –

+0

あなたはそれを上の任意のレベルを選ぶべきであることをどのように知っていますか? –

1

は、アレックスマルテッリのソリューションは、おそらくあなたが見つけることが最良です。もう1つのオプションは、モデルを変更できる場合は、リンクリストツリー構造からネストされたセットモデルに変更することです。

Joe Celkoさんにはa book on trees and hierarchiesがあり、さまざまな方法でモデル化でき、それぞれのメリットとデメリットをモデル化できます。おそらく、GoogleまたはGoogleグループを通じて、件名に関する多くの情報を見つけることができます。

ネストされたセットモデルの欠点の1つは、ツリー構造の変更がもう少し高価ですが、製品の場合は通常、更新するよりもはるかに多くを取得していることです。特にほとんどのビジネスケースではまれなカテゴリ間を移動します。ネストされたセットモデルを使用して

、次は何をしたいあなたを与えるだろう:

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. 区分が主キーです。

  2. 行レベルの説明がnullの場合、親行を参照してください。 Parent行にnullの説明がある場合は、親の親を参照してください。他の言葉では、祖先の最初のnullでない記述を使用します。

  3. 行レベルの説明がnull、およびNO祖先が非NULL説明と存在しない場合、全体的な記述は、例えばテーブルやテストデータを設定

ヌルです。

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 

出力は、カテゴリIDから最終的な説明へのマッピングです。

再利用の観点からは、私は上記のことを考えます。

+0

100以上のレベルの再帰があるまで、これは正常に動作します。その時点で、SQL ServerはCTEを停止します。しかし、ほとんどの場合、人々はそのような多くのレベルやデータを扱っていません。残念ながら、私は幸運な少数の一人です。 :) –

1

あなたは再帰的に親木を歩く必要がある場合は、answer from Alexを参照してください。 1つのレベルのみが必要な場合は、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 
関連する問題