今天,一個同事說有個查詢比較複雜,需求是:查詢機構下的用戶數(包括下面所有機構用戶),同時還要統計下屬機構的用戶數。sql
業務要求:要統計總公司下的用戶,還要統計總公司下屬的所有機構(技術部,分公司等)的用戶數,數據庫
同時還要統計技術部,這時統計技術部的用戶,還可能包含技術一部,技術二部,技術三部,可能技術一部下面還包含測試部等等部門的用戶app
依此類推,統計下面的技術一部,和技術一部下面的測試部函數
同事說這樣的話要在程序裏遞歸查詢所有機構,就能夠獲得結果,要寫不少條sql語句,能不能用一條sql查詢出來。測試
後來本身試着用一個SQL語句統計出各個機構(包含下屬機構)的用戶數據,在SQL server 2005裏有CTE實現遞歸查詢。但只能查詢一級的數據,如查詢總公司的能夠,但下面個部門,各個子公司就很差查詢了總數了。並且在一條sql語句實現遞歸不太可能,這時考慮一下,發現用表值函數來實現,結合Cross apply來查詢其下屬機構的用戶數。如下是實現T_SQL代碼:spa
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: 鄭平
-- Create date: 2008年8月26日11:14:15
-- Description: 返回機構下面的所有機構(包含本機構)
-- =============================================
CREATE FUNCTION subOrgs
(
@orgid varchar(32)
)
RETURNS @tab table(id varchar(32))
AS
BEGIN
;
with org(orgid)
as
(
select a.oid from orgunitlink a
where a.pid=@orgid
union all
select c.oid
from orgunitlink c inner join org aa
on aa.orgid=c.pid
)
insert into @tab select orgid from org union select @orgid
RETURN
END
GO.net
select t.objname,sum(y.num) num,t.id from
(select b.objname,count(*) num,b.id from humres a inner join
orgunit b on a.orgid=b.id
inner join orgunitlink c on c.oid=b.id where a.isdelete=0 and
a.workstatus<>'402881ea0b1c751a010b1cd2ae770008'
group by b.objname,b.id,c.pid)t
CROSS APPLY subOrgs(id) f
inner join
(select b.objname,count(*) num,b.id from humres a inner join
orgunit b on a.orgid=b.id
inner join orgunitlink c on c.oid=b.id where a.isdelete=0 and
a.workstatus<>'402881ea0b1c751a010b1cd2ae770008'
group by b.objname,b.id,c.pid)
y on y.id=f.id group by t.objname,t.id order by 2 descserver
以上查詢的速度很快,並且不使用遞歸查詢數據庫,是一個比較好的解決辦法,下面是查詢結果:blog