sql >> Databasteknik >  >> RDS >> Sqlserver

Skapa trädfråga från numerisk mappningstabell i SQL (med separatorfält)

Det här borde komma dig ganska nära... Men jag måste erkänna att jag inte helt förstår logiken... Varför är "HasChild" satt till 1 på 9401/Acc12?

Prova med detta. Numreringen är partitionerad av SourceCast. Det betyder att båda uppsättningarna (eller många uppsättningar behandlas som en uppsättning vardera, beroende på SourceCast. Dessutom finns det ett körande ID, som i ditt exempel:

CREATE TABLE Account(AccountID   NVARCHAR(50) NOT NULL
  ,AccountName NVARCHAR(50) NOT NULL
  ,SourceCast  INTEGER  NOT NULL
  ,PRIMARY KEY (AccountID,SourceCast));

 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11',N'Acc11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11',N'Acc11/11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/12',N'Acc11/12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/111',N'Acc11/111',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/001',N'Acc11/11/001',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/002',N'Acc11/11/002',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15',N'Acc15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15',N'Acc15/15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/12',N'Acc15/12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/111',N'Acc15/111',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/001',N'Acc15/15/001',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/002',N'Acc15/15/002',9402);
GO

WITH DistinctSourceCasts AS (SELECT DISTINCT SourceCast FROM Account)
SELECT *
INTO #tempHierarchy
FROM
(
    SELECT SourceCast
          ,CAST(SourceCast AS NVARCHAR(50)) AS AccountID 
          ,CAST(SourceCast AS NVARCHAR(50)) AS AccountName
          ,0 AS ID
          ,0 AS HierarchyLevel
          ,'' AS ParentPath
          ,'' AS ownID
          ,'' AS ancestorID 
    FROM DistinctSourceCasts
    UNION ALL
    SELECT SourceCast
          ,AccountID
          ,AccountName
          ,ROW_NUMBER() OVER(PARTITION BY SourceCast ORDER BY LEN(AccountID)-LEN(REPLACE(AccountID,'/','')),AccountID) AS ID
          ,Extended.HierarchyLevel
          ,STUFF(
           (
             SELECT '/' + A.B.value('.','varchar(10)')
             FROM Extended.IDsXML.nodes('/x[position() <= sql:column("HierarchyLevel")]') AS A(B)
             FOR XML PATH('')
           ),1,2,'') AS ParentPath
          ,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")+1][1]','varchar(10)') AS ownID
          ,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")][1]','varchar(10)') AS ancestorID
    FROM Account
    CROSS APPLY(SELECT LEN(AccountID)-LEN(REPLACE(AccountID,'/','')) + 1 AS HierarchyLevel
                      ,CAST('<x></x><x>' + REPLACE(AccountID,'/','</x><x>') + '</x>' AS XML) AS IDsXML) AS Extended
) AS tbl;

UPDATE #tempHierarchy SET ParentPath = SourceCast,ancestorID=SourceCast WHERE HierarchyLevel=1;
UPDATE #tempHierarchy SET ownID=SourceCast WHERE HierarchyLevel=0;


WITH RecursiveCTE AS
(
    SELECT th.*
           ,CAST(NULL AS BIGINT) AS ParentID 
           ,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=th.AccountID) THEN 1 ELSE 0 END AS HasChild
    FROM #tempHierarchy AS th WHERE th.HierarchyLevel=0
    UNION ALL
    SELECT r.SourceCast
          ,sa.AccountID
          ,sa.AccountName
          ,sa.ID
          ,sa.HierarchyLevel
          ,sa.ParentPath
          ,sa.ownID
          ,sa.ancestorID
          ,(SELECT x.ID FROM #tempHierarchy AS x WHERE x.AccountID=sa.ParentPath)
          ,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=sa.AccountID) THEN 1 ELSE 0 END AS HasChild
    FROM RecursiveCTE AS r
    INNER JOIN #tempHierarchy AS sa ON sa.HierarchyLevel=r.HierarchyLevel+1 
                                       AND r.AccountID=sa.ParentPath
                                       AND r.SourceCast=sa.SourceCast
)
SELECT SourceCast
      ,r.AccountID
      ,r.AccountName
      ,ROW_NUMBER() OVER(ORDER BY SourceCast,HierarchyLevel,ParentID,ID) AS ID
      ,r.ID AS GroupedID
      ,r.ParentID
      ,r.HierarchyLevel
      ,r.HasChild
FROM RecursiveCTE AS r

DROP TABLE #tempHierarchy;

Resultatet:

+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| SourceCast | AccountID | AccountName  | ID | GroupedID | ParentID | HierarchyLevel | HasChild |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 9401      | 9401         | 1  | 0         | NULL     | 0              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11        | Acc11        | 2  | 1         | 0        | 1              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 12        | Acc12        | 3  | 2         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 13        | Acc13        | 4  | 3         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11     | Acc11/11     | 5  | 4         | 1        | 2              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/111    | Acc11/111    | 6  | 5         | 1        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/12     | Acc11/12     | 7  | 6         | 1        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11/001 | Acc11/11/001 | 8  | 7         | 4        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11/002 | Acc11/11/002 | 9  | 8         | 4        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 9402      | 9402         | 10 | 0         | NULL     | 0              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 12        | Acc12        | 11 | 1         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 13        | Acc13        | 12 | 2         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15        | Acc15        | 13 | 3         | 0        | 1              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/111    | Acc15/111    | 14 | 4         | 3        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/12     | Acc15/12     | 15 | 5         | 3        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15     | Acc15/15     | 16 | 6         | 3        | 2              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15/001 | Acc15/15/001 | 17 | 7         | 6        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15/002 | Acc15/15/002 | 18 | 8         | 6        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+



  1. Vill du begränsa värdet på ett MySQL-fält till ett specifikt intervall (decimalvärden)

  2. Hämta den sista posten i varje grupp - MySQL

  3. Hur kan jag spara data från xml till sql 2008?

  4. PostgreSQL:Gruppering och filtreringstabell, med villkor för att det inte finns