Sql-Server

從 SQL 表中獲取嵌套/分層數據

  • June 19, 2017

我在“標籤”和“任務”之間有一個表格關係。它是 M:M。該關係映射在表“ TagTaskMapping ”中。

TagAssignment 表儲存 Tag 和日期之間的關係。所以一個標籤可以映射到一個日期(期間)。

我想從 sql 輸出嵌套層次結構。

SQL 表:

-- tag assigned to a specific date
CREATE TABLE [dbo].[TagAssignment](
   [TagAssignmentID] [int] IDENTITY(1,1) NOT NULL,
   [TagID] [int] NOT NULL,
   [Period] [date] NOT NULL
);

-- task(s) mapped to tag(s)
CREATE TABLE [dbo].[TagTaskMapping](
   [TagID] [int] NOT NULL,
   [TaskID] [int] NOT NULL
);

-- tag table
CREATE TABLE [dbo].[Tag](
   [TagID] [int] IDENTITY(1,1) NOT NULL,
   [TagName] [nvarchar](150) NOT NULL
)

TagAssignment 映射表數據:

TagAssignmentID TagID   Period
24                3    31/05/2017
14                2    31/05/2017

TagTaskMapping 表數據:

TagID   TaskID
 2       1
 2       2
 2       3
 3       1
 3       3

這是我的查詢

DECLARE @Period datetime = '2017-05-31'    
;WITH CTE_TagAssignment
AS
(
   -- GET TAG(S) Assigned to selected PERIOD
   SELECT 
        ta.TagID
       ,t.TagName
       ,null as 'Task'
   FROM dbo.TagAssignment ta
   INNER JOIN 
       dbo.Tag t
        ON t.TagID = ta.TagID
   WHERE ta.Period = @Period

   UNION ALL

   /**USING RECURSION!!!!**/
   -- foreach above tag assigned to a period, get it's associated task(s)
   SELECT 
       ttm.TagID
       ,null AS 'TagName'
       ,ttm.TaskID as 'Task'
   FROM CTE_TagAssignment cta
   INNER JOIN 
       dbo.TagTaskMapping ttm
       ON cta.TagID = ttm.TagID
)  
SELECT *
FROM CTE_TagAssignment  
OPTION (MAXRECURSION 100);

但是,我收到此錯誤:語句終止。在語句完成之前,最大遞歸 100 已用完。

這是我想要的層次結構輸出……

TagID   TagName   Task
2       Level 5 
                  1
                  2
                  3
3       Level 3 
                  1
                  3

恕我直言,您不需要遞歸解決方案,您可以使用簡單的 JOIN 來獲得它。

DECLARE @Period datetime = '20170531';

SELECT     t.TagID, t.TagName, tm.TaskID
FROM       TagAssignment ta
INNER JOIN TagTaskMapping tm
ON         tm.TagID = ta.TagID
INNER JOIN Tag t
ON         t.TagID = tm.TagID
WHERE      ta.Period = @period
ORDER BY   tm.TagID, tm.TaskID;
GO
標籤ID | 標記名 | 任務ID
----: | :------ | -----:
 2 | 5 級 | 1
 2 | 5 級 | 2
 2 | 5 級 | 3
 3 | 3 級 | 1
 3 | 3 級 | 3

dbfiddle在這裡

注意:這基本上是 McNets 解決方案的變體,具有您要求的格式,以及對您的 CTE 問題的解釋。

正如 McNets 所指出的,您實際上沒有遞歸查詢。在遞歸 CTE 中,查詢的遞歸部分通常有一些條件迫使它停止。它最終會遇到一組不生成行的值。你的沒有這樣的停止條件;它只會不斷重複生成新行。

您真正的問題是格式問題。

這應該以您想要的格式獲得您想要的結果:

SELECT CASE WHEN Header = 1 THEN CAST(TagID as varchar(20)) ELSE '' END as TagID
     ,CASE WHEN Header = 1 THEN TagName ELSE '' END as TagName
     ,CASE WHEN Header = 1 THEN '' ELSE CAST(TaskId as varchar(20)) END as TaskID
 FROM (
       SELECT DISTINCT
              t.TagID, t.TagName, CAST(NULL as int) as TaskID, 1 as Header
         FROM TagAssignment ta
                INNER JOIN TagTaskMapping tm ON ta.TagID = tm.TagID
                INNER JOIN Tag t ON ta.TagID = t.TagID
        WHERE ta.Period = @period
       UNION ALL
       SELECT t.TagID, t.TagName, tm.TaskID, 0 as Header
         FROM TagAssignment ta
                INNER JOIN TagTaskMapping tm ON ta.TagID = tm.TagID
                INNER JOIN Tag t ON ta.TagID = t.TagID
        WHERE ta.Period = @period
      ) sq
ORDER BY sq.TagID, Header DESC, sq.TaskID;

檢查dbfiddle(再次基於 McNets 所做的工作)。

引用自:https://dba.stackexchange.com/questions/176619