web-dev-qa-db-fra.com

Donnez des données imbriquées / hiérarchiques de la table SQL

J'ai une relation de table entre "tag" et "tâche". C'est m: m. La relation est mappée dans la table ' tagtakmapping '.

La table TagAssignment stocke la relation entre une balise et une date. Donc, une balise peut être mappée à une seule date (période).

Je veux émettre une hiérarchie imbriquée de SQL.

Tables 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
)

Tableau de mappage TagAssignment Données :

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

Données de table TagTaskMapping :

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

Voici mon Query ...

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);

Cependant, je reçois cette erreur: la déclaration terminée. La récursion maximale 100 a été épuisée avant la fin de la déclaration.

C'est la hiérarchie sortie J'aimerais ...

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

IMHO Vous n'avez pas besoin d'une solution récursive, vous pouvez l'obtenir en utilisant une jointure simple.

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
 Tagide | TagName | Taskid 
 ----: | : --- -----: [.____] 2 | NIVEAU 5 | 1 [.____] 2 | NIVEAU 5 | 2 [.____] 2 | NIVEAU 5 | 3 [.____] 3 | NIVEAU 3 | 1 
 3 | NIVEAU 3 | 3 

dbfiddle --- (ici

2
McNets

Remarque: Il s'agit essentiellement d'une variation de la solution McNets, avec le formatage que vous avez demandé et une explication du problème avec votre CTE.

Comme les note McNets, vous n'avez pas vraiment de requête récursive. Dans une CTE récursive, la partie récursive de la requête a normalement une certaine condition qui le force à s'arrêter; Il a finalement rencontré un ensemble de valeurs qui ne génèrent aucune ligne de lignes. Le vôtre ahs pas de telles conditions d'arrêt; Il suffit de continuer à générer les nouvelles lignes à plusieurs reprises.

Votre vrai problème est un problème de formatage.

Cela devrait obtenir les résultats que vous souhaitez, dans le format souhaité:

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;

Vérifiez le dbfiddle (à nouveau, sur la base du travail effectué par McNet).

1
RDFozz