前幾天有一個需求很頭痛,部門是有上下級關系的,在給部門的經理賦予角色和權限的時候,通常我們都會認為假如經理A的部門是1,那么我給了他部門1 的管理權限,那么1的下級部門101,102,103 “自然而然的”都應該給他管理。
這個自然而然可不是想當然的那么自然,尤其系統沒有設置批量添加功能的時候,靠人工一個個的去添加下級部門真的是不現實。更過分的是,用戶要求整個公司的管理人員都要自動的擁有其所在部門的所有下級部門的某個權限,emmmm,煩死了,領導那么多,做事的小弟卻只有一個,一個個手動添加到何時???
由於整個系統都是依賴sql存儲過程,別問我為什么不寫java啊net啊c#啊什么的,這個系統是公司購買的,全部都是存儲過程,幾千上萬個吧,幾千行的存儲過程能把人看瞎咯!沒辦法只能隨行就市寫起來咯。
思路也很清楚,首先要把這些管理人員和所在部門找到,這是其一,其二是要把這些管理人員的下級部門找到,這兩個都找到以后,要順序循環管理人員,然后把他的部門和權限關聯起來。說起來容易做起來難,尤其我的存儲過程還沒達到精通的程度,也是反復琢磨,終於給搞出來了。
以下就是具體代碼,僅供參考:
首先准備部門和下級部門數據,這個就比較簡單了,一個簡單的遞歸查詢,寫成存儲過程以便調用。
CREATE PROCEDURE [dbo].[rsp_selectTreeofsubDep] --查詢下級部門 -- Add the parameters for the stored procedure here @depid int --父部門id AS BEGIN with cte as ( select d.depID ,d.AdminID from Department d where DepID = @depid union all select d.DepID ,d.AdminID from Department d inner join cte o on o.DepID = d.AdminID ) select DepID from cte END GO
然后就是主存儲過程,用來循環批量插入數據的:
CREATE Procedure [dbo].[rsp_insertMultitiesofDep] --代理部門批量插入 AS DECLARE @i int, @RoleID int,@Depid int ----循環角色ID DECLARE @UserDepidTemp TABLE --部門負責人代號和其所在部門 ( UserID varchar(10), Depid int ) DECLARE @subDepidTemp TABLE --部門負責人的下級部門 ( Depid int ) DECLARE @UserDepidRoleTemp TABLE --部門負責人角色和其所在部門 ( RoleID int, Depid int, FlagID TINYINT ) BEGIN --整理部門負責人代號和所在部門 ,將部門負責人的用戶名和部門編號放到臨時表 insert into @UserDepidTemp
select UserID,Depid from employee where UserID in (select distinct e.UserID from employee e left join Department d on e.DepID = d.DepID join employee p on e.NID = p.MANAGER ) --整理部門負責人的角色ID和部門,將角色表的部門經理的角色和用戶表的部門經理的部門放到臨時表,標志位全部置0 insert into @UserDepidRoleTemp(RoleID,Depid,FlagID) select RoleID ,depid ,0 from USER_ROLE u left join @UserDepidTemp b on u.UserID = b.UserID where depid is not null
---開始循環角色,用戶取自上面的角色代號和部門代號的臨時表 SET @i=1 WHILE( @i>=1) BEGIN SELECT @RoleID='' SELECT TOP 1 @RoleID = RoleID FROM @UserDepidRoleTemp WHERE FlagID=0 --順序讀取表中的第一個角色用戶,即當前角色用戶 SET @i=@@ROWCOUNT --受影響行數為1 select @Depid='' select top 1 @Depid = Depid from @UserDepidRoleTemp WHERE RoleID=@RoleID --獲取當前用戶角色所在部門作為父部門,以便下一行查詢下級部門列表 insert into @subDepidTemp EXEC rsp_selectTreeofsubDep @Depid --獲取下級部門結果集 insert into ROLE_DEPT (ROLEID,DepID) SELECT @Roleid,Depid from @subDepidTemp --將當前循環表中的用戶角色和查詢到的下級部門放入角色部門表 IF @i<=0 GOTO Return_Lab --當i小於0時跳出循環 IF @@error=0 delete from @subDepidTemp --千萬記得要刪除下級部門臨時表,這個表放的是當前角色用戶的下級部門 UPDATE @UserDepidRoleTemp SET FlagID=1 WHERE ID = @ID --將用戶角色和所在部門的標志位置1,下次循環將跳過該數據 Return_Lab: END END GO
嗯,如上,就上面這個存儲過程,現在來看也不復雜,可是我還是寫了好久,好幾個地方數據都拿錯了,導致測試表的結果總不對。
當然現在這種批量事務一般都用其他服務端語言解決了,仍然用純sql實現的方案比較少了,我也是趕鴨子上架硬着頭皮寫,總算寫出來了也算完成了一件事。
換新工作后每天就是sql,各種眼花繚亂的sql整到沒脾氣,存儲過程雖然也能寫,但是更深層次的事務管理和鎖啊同步啊互斥啥的都沒理解,能用就行,還需慢慢修行吧!也不知道純sql能找到工作否。