web-dev-qa-db-ja.com

以下のクエリから階層値を取得するにはどうすればよいですか?

Categoryという名前の列があるCategoryIDという名前のテーブルがあります。同じテーブルにfParentCategoryIDという参照列があります。

すべてのカテゴリIDとそのサブカテゴリIDをカンマで区切る必要があります。 例-親カテゴリID 10が1で、親カテゴリID 20が10の場合、カテゴリID 20を印刷するとき、両方を印刷する必要がありますカンマ区切り値での親としての1および10。

以下のクエリを試しましたが、NULL列にParChildが表示されます。助けてください。

;WITH
  cteReports 
  AS
(
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] = 1,
       ParChild=cast(CAST(c.fParentCategoryID AS VARCHAR(200)) + ',' + CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL
UNION ALL
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] + 1,
       ParChild = ParChild + ',' + CAST(c.CategoryID AS VARCHAR(200))
FROM   retail.Category c
        JOIN cteReports r
            ON  c.fParentCategoryID = r.CategoryID

)

SELECT *
FROM   cteReports cr 

このスクリプト を使用して、テーブルを作成してデータを入力します。 (注:質問の本文には30Kの制限があります。そのため、Pastebinを使用してコードをコピーして参照する必要がありました)

8
mayooran

私はあなたの例のデータであなたの結果を再現することができました。

問題は、再帰CTE(最初の選択ステートメント)の「ベース」の場合、fParentCategoryIDがnullであるレコードを取得し、fParentCategoryIDを「子」を追加する準備ができている文字列にキャストすることです。ただし、この段階ではまだ 'string'はNULL値です(SELECT CAST(NULL AS VARCHAR(200))などで試してください)。

2番目のselectステートメントは、他の文字列値をNULLに追加しようとしますが、デフォルトでは、データベースオプション "concat nullはnullを生成します"は、何かをNULL値に連結しようとすると、それを単にNULLとして取得するだけでなく、空の文字列。

このクエリではCONCAT_NULL_YIELDS_NULL OFFを設定できますが、これは非推奨であり、SQL Serverの将来のバージョンでは最終的に削除されます(したがって、本番用コードに追加しないでください!)

より良い方法は、fParentCategoryIDを文字列にキャストするのではなく、最初のselectステートメントを使用することです。CategoryIDをキャストするだけです。親はNULLであるため、空である必要があります。

SELECT c.CategoryID,
   c.fParentCategoryID,
   [level] = 1,
   ParChild=cast(CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL

そのselectステートメントでデータにnull値とnull以外の値が混在している可能性がある場合は、ISNULLを使用してnullを空の文字列として扱うこともできます。

"、461,464"のような値を取得するときに生成されるParChild値のクリーンアップが必要になる可能性があるため、最初のカンマを削除する必要がある場合があります。

3
seventyeightist