Sql-Server
從 SQL 表中獲取嵌套/分層數據
我在“標籤”和“任務”之間有一個表格關係。它是 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 所做的工作)。