56

特定の方法で、ツリーの順序付けられた階層を取得する必要があります。問題のテーブルは次のようになります (すべての ID フィールドは一意の識別子です。例のためにデータを単純化しました)。

EstimateItemID EstimateID ParentEstimateItemID ItemType
-------------- ---------- -------------------- ------ --
       1 ヌル積
       2 A 1 製品
       3A2サービス
       4 ヌル積
       5A4品
       6A5サービス
       7A1サービス
       8A4品

ツリー構造のグラフィカル ビュー (* は「サービス」を示します):

           あ
       ___/ \___
      / \
    1 4
   / \ / \
  2 7* 5 8
 / /
3* 6*

このクエリを使用して、階層を取得できます ('A' が一意の識別子であると仮定してください。実際にはそうではないことがわかっています)。

DECLARE @EstimateID uniqueidentifier
SELECT @EstimateID = 'A'

;WITH temp as(
    SELECT * FROM EstimateItem
    WHERE EstimateID = @EstimateID

    UNION ALL

    SELECT ei.* FROM EstimateItem ei
    INNER JOIN temp x ON ei.ParentEstimateItemID = x.EstimateItemID
)

SELECT * FROM temp

これにより、EstimateID 'A' の子が得られますが、テーブルに表示される順序になります。すなわち:

見積もりアイテムID
--------------
      1
      2
      3
      4
      5
      6
      7
      8

残念ながら、次の制約に従う結果セットを持つ順序付けられた階層が必要です。

1. 各ブランチをグループ化する必要があります
2. ItemType 'product' および親を持つレコードが最上位ノードです
3. 最上位ノードの後に​​グループ化された ItemType 'product' および NULL 以外の親を持つレコード
4. ItemType 'service' を持つレコードは、ブランチの最下位ノードです

したがって、この例では、結果が必要な順序は次のとおりです。

見積もりアイテムID
--------------
      1
      2
      3
      7
      4
      5
      8
      6

これを達成するには、クエリに何を追加する必要がありますか?

4

3 に答える 3

21

これは、上からの Fabio の素晴らしいアイデアへのアドオンです。彼の元の投稿への返信で言ったように。他の人が簡単にフォローできるように、より一般的なデータ、テーブル名、およびフィールドを使用して彼のアイデアを再投稿しました.

ありがとうファビオ!ところで素晴らしい名前。

最初に使用するデータ:

CREATE TABLE tblLocations (ID INT IDENTITY(1,1), Code VARCHAR(1), ParentID INT, Name VARCHAR(20));

INSERT INTO tblLocations (Code, ParentID, Name) VALUES
('A', NULL, 'West'),
('A', 1, 'WA'),
('A', 2, 'Seattle'),
('A', NULL, 'East'),
('A', 4, 'NY'),
('A', 5, 'New York'),
('A', 1, 'NV'),
('A', 7, 'Las Vegas'),
('A', 2, 'Vancouver'),
('A', 4, 'FL'),
('A', 5, 'Buffalo'),
('A', 1, 'CA'),
('A', 10, 'Miami'),
('A', 12, 'Los Angeles'),
('A', 7, 'Reno'),
('A', 12, 'San Francisco'),
('A', 10, 'Orlando'),
('A', 12, 'Sacramento');

再帰クエリは次のとおりです。

-- Note: The 'Code' field isn't used, but you could add it to display more info.
;WITH MyCTE AS (
  SELECT ID, Name, 0 AS TreeLevel, CAST(ID AS VARCHAR(255)) AS TreePath
  FROM tblLocations T1
  WHERE ParentID IS NULL

  UNION ALL

  SELECT T2.ID, T2.Name, TreeLevel + 1, CAST(TreePath + '.' + CAST(T2.ID AS VARCHAR(255)) AS VARCHAR(255)) AS TreePath
  FROM tblLocations T2
  INNER JOIN MyCTE itms ON itms.ID = T2.ParentID
)
-- Note: The 'replicate' function is not needed. Added it to give a visual of the results.
SELECT ID, Replicate('.', TreeLevel * 4)+Name 'Name', TreeLevel, TreePath
FROM  MyCTE 
ORDER BY TreePath;
于 2016-10-29T20:19:18.890 に答える
0

CTEの結果に以下を追加する必要があると思います...

  1. BranchID = ブランチを一意に識別するある種の識別子。より具体的でないことを許してください。しかし、あなたのニーズに合ったブランチを特定するものはわかりません. あなたの例は、すべてのブランチがルートに戻るバイナリ ツリーを示しています。
  2. ItemTypeID (たとえば) 0 = 製品、1 = サービス。
  3. 親 = 親を識別します。

それらが出力に存在する場合、クエリからの出力を別の CTE またはクエリの FROM 句として使用できるはずです。BranchID、ItemTypeID、Parent で並べ替えます。

于 2013-08-07T15:35:18.307 に答える