2016-04-14 28 views
2

我有這個結構的圖:SQL查詢來讀取一定數量的記錄嵌套數據

EntryId | EntryName | ParentEntryId | Depth | DatePosted 

我想要做的就是寫一個SQL查詢,將帶來第2項與深度= 0以及第一個後代(基於ParentEntryId)。下面,我提供了一個示例輸出。

EntryId | EntryName | ParentEntryId | Depth | DatePosted | ChildCount 
1  | a   | NULL   | 0  | 1/12/2012 | 2 
4  | b   | 1    | 1  | 1/14/2012 | 5 
13  | c   | 1    | 1  | 1/15/2012 | 3 
3  | d   | NULL   | 0  | 1/11/2012 | 1 
12  | e   | 3    | 1  | 1/14/2012 | 0 

我知道我可以把這些條目與深度= 0輕鬆這樣的:

SELECT TOP 10 FROM Entries WHERE Depth=0 ORDER BY DatePosted DESC 

但是,我不知道如何把相關的子項。例如,對於Id = 1的主條目,我想要帶入其ParentEntryId = 1的條目(第一後裔)。我還需要將這些第一後代的子條目的計數。有任何想法嗎?

+0

通過子條目您是指該條目的所有子代或只是下一個後代? – DhruvJoshi

+0

@DhruvJoshi只是後裔和子孫的次數 – renakre

+0

這裏是一個很好的開始。 http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

回答

1

您還可以遞歸CTE做到這一點。你應該確保性能滿足你的標準,但如果你想利用這個在一個大的記錄集上

;WITH cte AS (
    SELECT [EntryId], 
      [EntryName], 
      [ParentEntryId], 
      [Depth], 
      [DatePosted], 
      [EntryId] [Root], 
      ROW_NUMBER() OVER (ORDER BY DatePosted DESC) [Rn], 
      CAST(EntryId AS VARCHAR(MAX)) [Path] 
    FROM Entries 
    WHERE [Depth] = 0 
    UNION ALL 
    SELECT e.[EntryId], 
      e.[EntryName], 
      e.[ParentEntryId], 
      e.[Depth], 
      e.[DatePosted], 
      [Root], 
      Rn, 
      [Path] + ',' + CAST(e.EntryId AS VARCHAR(MAX)) 
    FROM Entries e 
      JOIN cte ON cte.EntryID = e.ParentEntryId 
) 
SELECT [EntryId], 
     [EntryName], 
     [ParentEntryId], 
     [Depth], 
     [DatePosted], 
     ChildCount 
FROM cte c1 
     OUTER APPLY (SELECT COUNT (*) - 1 AS ChildCount 
        FROM cte c2 
        WHERE c2.[Path] LIKE c1.[Path] + '%' 
        ) oa 
WHERE Rn <= 2 -- only gets the first 2 records with depth = 0 
     AND Depth <= 1 -- limit to only top level child records 
ORDER BY [Root], 
     [ParentEntryID] 
+0

這會讓ChildCount成爲_total_後代數量,而不是_first_後代的數量。我把OP的問題理解爲只想要孩子的數量,而不是子孫的數量等等,但這個問題還不完全清楚。 – Stainy

+0

感謝您的答案,但UNION ALL會返回重複條目。 – renakre

0

你有前10名,但沒有秩序,所以你的邏輯從一開始就有缺陷。您也沒有列出任何列。作爲一個純粹的猜測,因爲你沒有提供太多的細節,我正在想這樣的事情。

select [Columns] 
from Entries 
where ParentEntryID in 
(
    select top 10 EntryID 
    from Entries 
    where Depth = 10 
    order by SomeColumn 
) 

或者你可能需要一個遞歸cte來獲得每個樹下的整棵樹嗎?

2

基於更新後的問題,下面的查詢將產生完美的結果

SELECT 
    EntryId , EntryName , ParentEntryId , Depth , DatePosted, ChildCount 
    FROM 
    ( 
     SELECT 
     TOP 10 
      E1.EntryId , E1.EntryName , E1.ParentEntryId , E1.Depth , E1.DatePosted, 
      (
      SELECT 
       COUNT(1) 
      FROM Entries E2 
       WHERE E2.ParentEntryID =E1.EntryID 
      ) as ChildCount 
     FROM Entries E1 
     WHERE E1.Depth=0 

     UNION 

     SELECT 
     E1.EntryId , E1.EntryName , E1.ParentEntryId , E1.Depth , E1.DatePosted, 
     (
      SELECT 
      COUNT(1) 
      FROM Entries E3 
      WHERE E3.ParentEntryID =E1.EntryID 
      ) as ChildCount 
     FROM Entries E1 
     LEFT JOIN Entries E2 ON E1.ParentEntryID= E2.EntryID AND E2.Depth=0 
    ) 
    ORDER BY ParentEntryID , Depth ASC, DatePosted 
+0

這是有道理的,我會盡量讓你張貼,謝謝! – renakre

+0

我認爲'UNION'之後的查詢需要以某種方式與'UNION'之前的查詢連接。否則,它將返回一些獨立於主條目的記錄(深度= 0)。 – renakre

+0

@renakre更新! – DhruvJoshi

1

沒有任何輸入數據很難給你一個準確的答案。不過,我認爲這樣的事情就是你要找的東西。

我用一個簡單的數據集來測試。我試着組腳本的佈局,所以你可以很容易地看到基礎上,ParentEntryID孩子的數量:

-- Create a table. 
DROP TABLE Entries 
CREATE TABLE Entries 
(
    EntryID   INT, 
    EntryName  VARCHAR(20), 
    ParentEntryID INT, 
    Depth   INT, 
    DatePosted  DATE  
); 

-- Populate the table 
INSERT INTO Entries VALUES 
(1, 'A', null, null, CURRENT_TIMESTAMP) 
,(73, 'C', 1, 0, CURRENT_TIMESTAMP) 

,(16, 'B', 73, 1, CURRENT_TIMESTAMP) 
,(85, 'G', 73, 1, DATEADD(DAY, 1, CURRENT_TIMESTAMP)) 
,(74, 'D', 73, 1, CURRENT_TIMESTAMP) 

,(75, 'E', 74, 2, CURRENT_TIMESTAMP) 
,(76, 'F', 74, 2, CURRENT_TIMESTAMP) 

,(86, 'H', 85, 3, DATEADD(DAY, 2, CURRENT_TIMESTAMP)) 
,(87, 'I', 85, 3, DATEADD(DAY, 2, CURRENT_TIMESTAMP)) 

,(88, 'J', 86, 4, DATEADD(DAY, 3, CURRENT_TIMESTAMP)) 

,(89, 'K', 88, 5, CURRENT_TIMESTAMP) 
,(90, 'L', 88, 5, CURRENT_TIMESTAMP) 
,(91, 'M', 88, 5, CURRENT_TIMESTAMP) 
,(92, 'N', 88, 5, CURRENT_TIMESTAMP); 

然後你可以使用遞歸公用表表達式。我已將TOP 2WHERE Depth = 0註釋掉,以提供更多結果。 (我認爲這使得基於少量測試數據更容易理解)。您可以將它們替換爲您的要求。

;WITH MyEntries (EntryID, ParentEntryID, EntryName, Depth, DatePosted) 
AS 
(
    -- Anchor 
    SELECT EntryID, ParentEntryID, EntryName, Depth, DatePosted 
    FROM Entries 
    --WHERE Depth = 0 
    UNION ALL 
    -- Recursive 
    SELECT Recurs.EntryID, Recurs.ParentEntryID, Recurs.EntryName, Recurs.Depth, Recurs.DatePosted 
    FROM Entries AS Recurs  
      INNER JOIN MyEntries AS Anchor 
       ON Recurs.EntryID = Anchor.ParentEntryID  
    --WHERE Recurs.Depth = 0  
) 
SELECT DISTINCT 
     --TOP 2     
     ME.EntryID 
     ,ME.ParentEntryID 
     ,ME.EntryName 
     ,ME.Depth 
     ,ME.DatePosted 
     ,COALESCE(VT.ChildCOunt, 0) AS 'ChildCount' 
FROM MyEntries AS ME 
LEFT JOIN (SELECT ParentEntryID, COUNT(1) AS 'ChildCount' 
      FROM Entries 
      GROUP BY ParentEntryID) AS VT 
     ON ME.EntryID = VT.ParentEntryID    
ORDER BY   
     ME.DatePosted; 

我不確定這是最有效的方法,但它似乎工作。