Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Buat Kueri Pohon Dari Tabel Pemetaan Numerik di SQL (Dengan Bidang Pemisah)

Ini akan membuat Anda cukup dekat... Tapi harus saya akui, bahwa saya tidak sepenuhnya memahami logikanya... Mengapa ada di 9401/Acc12 "HasChild" disetel ke 1 ?

Cobalah dengan ini. Penomoran dipartisi oleh SourceCast. Artinya, kedua set (atau banyak set diperlakukan sebagai satu set masing-masing, bergantung pada SourceCast. Selain itu, ada ID yang berjalan, seperti dalam contoh Anda:

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;

Hasilnya:

+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 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. Kompilasi ulang procs yang disimpan?

  2. Mengonversi antara SQL char dan C#

  3. Menyimpan data UTF-16/Unicode di SQL Server

  4. Ubah 'datetimeoffset' menjadi 'tanggal' di SQL Server (Contoh T-SQL)

  5. SQL Server FileStream cara mengisi kolom filestream