sql >> データベース >  >> RDS >> Sqlserver

SQL の数値マッピング テーブルからツリー クエリを作成する (特定の形式)

    最初の質問の回答を修正しました...

    テーブルがリレーション データをインデックス付きの列に直接保持する場合に最適です。テーブルの構造を変更する前に、次のことを試してみてください:

    テストデータを含むテーブル

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

    これにより、必要なデータが #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("階層レベル")+1][1]','varchar(10 )') AS ownID ,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")][1]','varchar(10)') AS 祖先IDINTO #tempHierarchyFROM @tblCROSS APPLY(SELECT LEN(AccountID) -LEN(REPLACE(AccountID,'/','')) + 1 AS HierarchyLevel ,CAST('' + REPLACE(AccountID,'/','') + '' AS XML) AS IDsXML) AS 拡張; 

    中間結果

    <前>+-----------+--------------+----+----------- ---+------------+-------+------------+|アカウント ID |アカウント名 | ID |階層レベル |親パス |所有ID |先祖ID |+-----------+--------------+----+--------------- --------------+-------+------------+| 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 |+-----------+--------------+----+--------------- --------------+-------+------------+

    そして今、私の最初の答えと同様の再帰的アプローチが行われます。しかし - 現在は実際のテーブルを使用しており、すべての文字列分割が既に行われているため、より高速になるはずです...

    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(#tempHierarchy AS x WHERE x.ParentPath=sa.AccountID から 1 を選択) 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.HasChildFROM RecursiveCTE AS rORDER BY HierarchyLevel,ParentID; 

    最後にクリーンアップします

    DROP TABLE #tempHierarchy; 

    最終結果はこちら

    <前>+-----------+--------------+----+----------+ ----+---------+|アカウント ID |アカウント名 | ID |親 ID |階層レベル | HasChild |+-----------+--------------+----+----------+----+---- ------------+---------+| 11 | Acc11 | 1 |ヌル | 1 | 1 |+----------+--------------+----+----------+---- ------------+---------+| 12 | Acc12 | 2 |ヌル | 1 | 1 |+----------+--------------+----+----------+---- ------------+---------+| 13 | Acc13 | 3 |ヌル | 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. MySQL CASE ... WHERE...THENステートメント

    2. PostgreSQLにトリガーが存在するかどうかを確認するにはどうすればよいですか?

    3. PostgreSQL:pgcryptoで列を暗号化する

    4. MySQLでprintステートメントをシミュレートするにはどうすればよいですか?