Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Utwórz zapytanie drzewa z tabeli mapowania numerycznego w SQL (z polem separatora)

To powinno cię przybliżyć... Ale muszę przyznać, że nie do końca rozumiem logikę... Dlaczego w 9401/Acc12 jest ustawione "HasChild" na 1?

Spróbuj z tym. Numeracja jest podzielona na partycje przez SourceCast. Oznacza to, że oba zestawy (lub wiele zestawów jest traktowanych jako jeden zestaw każdy, w zależności od SourceCast. Dodatkowo istnieje działający identyfikator, jak w twoim przykładzie:

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;

Wynik:

+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak znaleźć piątą najwyższą pensję w pojedynczym zapytaniu w SQL Server?

  2. Konwertuj „datetimeoffset” na „time” w SQL Server (przykłady T-SQL)

  3. Wysoka dostępność programu SQL Server:Dodaj nowy dysk do istniejącego wystąpienia klastra pracy awaryjnej

  4. Dlaczego miałby SqlServer select wybrać wiersze, które pasują i wiersze, które pasują i mają końcowe spacje?

  5. Przetwarzaj ciąg znaków oddzielonych przecinkami, aby utworzyć IN Lista ciągów w klauzuli Where