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

Buat Kueri Pohon Dari Tabel Pemetaan Numerik dalam SQL (Format Tertentu)

Saya mengubah jawaban saya yang diberikan di pertanyaan pertama...

Akan lebih baik, jika tabel Anda akan menyimpan data relasi secara langsung di kolom yang diindeks. Sebelum Anda mengubah struktur tabel, Anda dapat mencoba ini:

Tabel dengan data uji

DECLARE @tbl TABLE ( AccountID  VARCHAR(100), AccountName VARCHAR(100));
INSERT INTO @tbl VALUES 
 ('11','Acc11')
,('12','Acc12')
,('13','Acc13')
,('11/11','Acc11/11')
,('11/12','Acc11/12')
,('11/111','Acc11/111')
,('11/11/001','Acc11/11/001')
,('11/11/002','Acc11/11/002')
,('12/111','Acc12/111')
,('12/112','Acc12/112');

Ini akan mendapatkan data yang dibutuhkan ke dalam tabel temp yang baru dibuat bernama #tempHierarchy

SELECT AccountID
      ,AccountName
      ,ROW_NUMBER() OVER(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
INTO #tempHierarchy
FROM @tbl
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
;

Hasil antara

+-----------+--------------+----+----------------+------------+-------+------------+
| AccountID | AccountName  | ID | HierarchyLevel | ParentPath | ownID | ancestorID |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11        | Acc11        | 1  | 1              |            | 11    |            |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12        | Acc12        | 2  | 1              |            | 12    |            |
+-----------+--------------+----+----------------+------------+-------+------------+
| 13        | Acc13        | 3  | 1              |            | 13    |            |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11     | Acc11/11     | 4  | 2              | 11         | 11    | 11         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/111    | Acc11/111    | 5  | 2              | 11         | 111   | 11         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/12     | Acc11/12     | 6  | 2              | 11         | 12    | 11         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12/111    | Acc12/111    | 7  | 2              | 12         | 111   | 12         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 12/112    | Acc12/112    | 8  | 2              | 12         | 112   | 12         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11/001 | Acc11/11/001 | 9  | 3              | 11/11      | 001   | 11         |
+-----------+--------------+----+----------------+------------+-------+------------+
| 11/11/002 | Acc11/11/002 | 10 | 3              | 11/11      | 002   | 11         |
+-----------+--------------+----+----------------+------------+-------+------------+

Dan sekarang pendekatan rekursif serupa terjadi seperti pada jawaban pertama saya. Tapi - karena sekarang menggunakan tabel nyata dan semua pemisahan string telah terjadi - seharusnya lebih cepat...

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=1
    UNION ALL
    SELECT 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
)
SELECT r.AccountID
      ,r.AccountName
      ,r.ID
      ,r.ParentID
      ,r.HierarchyLevel
      ,r.HasChild
FROM RecursiveCTE AS r
ORDER BY HierarchyLevel,ParentID;

Dan akhirnya saya bersihkan

DROP TABLE #tempHierarchy;

Dan inilah hasil akhirnya

+-----------+--------------+----+----------+----------------+----------+
| AccountID | AccountName  | ID | ParentID | HierarchyLevel | HasChild |
+-----------+--------------+----+----------+----------------+----------+
| 11        | Acc11        | 1  | NULL     | 1              | 1        |
+-----------+--------------+----+----------+----------------+----------+
| 12        | Acc12        | 2  | NULL     | 1              | 1        |
+-----------+--------------+----+----------+----------------+----------+
| 13        | Acc13        | 3  | NULL     | 1              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 11/11     | Acc11/11     | 4  | 1        | 2              | 1        |
+-----------+--------------+----+----------+----------------+----------+
| 11/111    | Acc11/111    | 5  | 1        | 2              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 11/12     | Acc11/12     | 6  | 1        | 2              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 12/111    | Acc12/111    | 7  | 2        | 2              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 12/112    | Acc12/112    | 8  | 2        | 2              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 11/11/001 | Acc11/11/001 | 9  | 4        | 3              | 0        |
+-----------+--------------+----+----------+----------------+----------+
| 11/11/002 | Acc11/11/002 | 10 | 4        | 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. Menggunakan SqlDependency dengan Antrian bernama

  2. Konversi 'datetime2' menjadi 'datetimeoffset' di SQL Server (Contoh T-SQL)

  3. TransactSQL untuk menjalankan skrip TransactSQL lainnya

  4. Cara mengedit spesifikasi Identitas di SQL Server 2008

  5. Cara menggunakan parameter dengan LIKE di Sql Server Compact Edition