2016-12-02 18 views
0

我正在創建sql hirercky表如何擺脫超時錯誤,當使用mssql層次結構檢查constrint

這是我的代碼;

約束函數代碼

    alter Function Accounts.Types_Sub_Check_fn (@ID uniqueidentifier, @Sub Uniqueidentifier) returns int 
        begin 
        --declare @id uniqueidentifier = '8c7d4151-246c-476c-adf6-964ca9afdd3c' declare @sub uniqueidentifier = '47c2b6da-25fc-4921-adfa-b1f635bddde6' 
        declare @a int 
        declare @b int =(iif(@[email protected],2,0)) 

        ;with cte(id, lvl) as 
         (
         select f.sub, 
           1 
         from Accounts.Types as f 
         where f.id = @id 
         union all 
         select f.sub, 
           lvl + 1 
         from Accounts.Types as f 
          inner join cte as c 
          on f.id = c.id 
        ) 
         select @a = (select count (*) 
            from cte 
            where id [email protected]) + @b 


         option (maxrecursion 0) 


         return @a 
        end 
        go 

表代碼

create Table Accounts.Types 
         (
         ID uniqueidentifier not null CONSTRAINT DF_Accounts_Types_ID DEFAULT newid() CONSTRAINT PK_Accounts_Types_ID PRIMARY KEY NONCLUSTERED (ID) , 
         Name varchar(200) not null CONSTRAINT UQ_Accounts_Types_NAME UNIQUE (NAME), 
         Sub uniqueidentifier CONSTRAINT FK_Accounts_Types_Sub Foreign key references Accounts.Types , 
         Ctype uniqueidentifier CONSTRAINT FK_Accounts_Types_Ctype Foreign key references Accounts.Types , 
         insert_time datetime not null CONSTRAINT DF_Accounts_Types_Insert_Time DEFAULT getdate() , 
         insert_user uniqueidentifier CONSTRAINT DF_Accounts_Types_Insert_User DEFAULT'9EC66F53-9233-4A6C-8933-F8417D2BB5A9' , 
         ts timestamp, 
         INDEX IX_Accounts_Types_NAME#ASC CLUSTERED (Name ASC), 
         Constraint Check_Accounts_Types_Sub check (Accounts.Types_Sub_Check_fn(ID,Sub)<=1) 
         ) 
         go 

如果試圖插入itseft父此功能將得到2,結果(在子列)

它會給1,如果它已經是一個孩子,試圖插入作爲其父母

CHECK約束創建檢查父(分列)對任何ID不應該是其子或大孩子, 和本身不能是其母公司

當我嘗試插入數據,不符合檢查約束,它卡住,並給出一個超時錯誤,

如:

insert into Accounts.Types (ID, Name, Sub) 
    values ('607936b9-6f95-4989-8ebe-87a08807f43e','LLL','607936b9-6f95-4989-8ebe-87a08807f43e') 

這會給超時

任何人都可以幫助我,我需要擺脫超時錯誤;只有約束錯誤

+1

它看起來像通過構建一個CSV字符串,然後對它進行LIKE檢查父/子/自我關係。您可能可以直接使用遞歸CTE檢查關係,而無需構建CSV字符串。 –

+1

您是否排除了通過'hierarchyid'數據類型使用支持建模層次結構的構建? –

+1

如果您在「樹」中創建循環,則CTE將運行一段時間。 [This](http://stackoverflow.com/a/15081353/92546)答案顯示了一種方法來終止遞歸,如果檢測到循環。 – HABO

回答

1

簡單的問題 - 什麼時候你的遞歸結束,當你的ID和Sub是相同的值,並且你不限制maxrecursion或lvl?決不。它永遠不會結束。

values ('607936b9-6f95-4989-8ebe-87a08807f43e','LLL','607936b9-6f95-4989-8ebe-87a08807f43e') 

您必須刪除行ID = Sub或添加maxrecursion或添加級別限制或標準化您的表。

+0

你是對的,它永遠不會結束; becuz檢查後插入它的約束檢查 –

+0

剛剛更換的行-------------------------------------- ------------------------------------------- union all select f.sub, -------------------------------------------------- - - - - - - - - 至 - - - - - - - - - - - - - - - - - -------------------------------------------------- ------------------------- union all select iif(f.Sub = @sub,Null,f.sub),------ -------------------------------------------------- ----------使curent更新記錄的子列爲null以結束循環。 –

0
  alter Function Accounts.Types_Sub_Check_fn (@ID uniqueidentifier, @Sub Uniqueidentifier) returns int 
        begin 
        --declare @id uniqueidentifier = '00279c6b-df00-4144-810d-571fdb1c5109' declare @sub uniqueidentifier = 'bc887e7b-36d2-4ece-8ec1-720dc81a9de4' 
        declare @a int = 0 
        declare @b int =(iif(@[email protected],2,0)) 
        if @ID <> @sub 
        begin 
        ;with cte(id, lvl) as 
         (
         select f.Sub , 
           1 
         from Accounts.Types as f 
         where f.id = @sub 
         union all 
         select iif(f.Sub = @sub, Null, f.sub), 
           lvl + 1 
         from Accounts.Types as f 
          inner join cte as c 
          on f.id = c.id 
        ) 

         select @a = (select count (*) 
            from cte 
            where id [email protected]) 

     option (maxrecursion 0); 


         end 
        -- select @a + @b 


         return @a + @b 
        end 
        go