? 寫sql存儲過程經常需要調用一些函數來使處理過程更加合理,也可以使函數復用性更強,不過在寫sql函數的時候可能會發現,有些函數是在表值函數下寫的有些是在標量值下寫的,區別是表值函數只能返回一個表,標量值函數可以返回基類型。 舉個例子,當用戶刪除一個節點的時候,是需要將當前節點下的所有子節點都刪掉,如果程序只傳一個當前節點,那就需要寫一個函數來得到當前節點下的所有子節點,這些子節點的信息就可以放到一個表中返回。 ALTER FUNCTION testGetSubNodes ( -- Add the parameters for the function here @nodeId int ) RETURNS @t TABLE ( -- Add the column definitions for the TABLE variable here id bigint identity(1,1) not null, nodeIds int , nodeName varchar(500) ) AS BEGIN -- Fill the table variable with the rows for your result set insert into @t values(@nodeId,'header'); while exists( select nodeid from dbo.Tree where parentid in (select nodeIds from @t) and nodeid not in(select nodeIds from @t)) begin insert into @t select nodeid, nodename from dbo.Tree where parentid in (select nodeIds from @t) end RETURN END 這個函數的主要功能就是返回當前節點下的所有子節點,在存儲過程中寫 select * from testGetSubNodes(nodeId)就可以返回表中的數據了。 再寫一個標量值函數 ALTER FUNCTION [dbo].[testGetSubNodes_] ( @nodeId int ) RETURNS int AS BEGIN declare @nodeCount int select @nodeCount=5 from MenuTree return @nodeCount END 這個函數很簡單返回一個整型值,然后就可以在存儲過程中調用了,不過調用的方式有所不同,象上面的表值函數調用是不需要所有者的,只要寫函數名稱就可以,對于標量值函數來說,是需要加上所有者的,比如所有者是dbo select dbo.testGetSubNodes_,這樣就可以返回5,如果不加dbo,那sql會不認識這個函數。 ? 以下是本人寫的例子 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author:??<yuzt> -- Create date: <2010-01-20 2:27 > -- Type: 多語句表值函數 -- Description:?<判斷多次回錄的時間是否在結算周期內.在周期內可以回錄返回0,否則返回1> -- 調用方法:SELECT * FROM dbo.ReadytestFunc('2010-2-28',1,107) --SELECT * FROM dbo.F_IsOverFeedBackTime('2009-2-28',1,107) -- ============================================= ALTER FUNCTION dbo.F_IsOverFeedBackTime ( ?@applyorderTime DATETIME , ?@RegionID INT , ?@ModuleID INT ) RETURNS @table TABLE (bsettle DATETIME,esettle DATETIME,returnval INT) AS BEGIN ?-- Fill the table variable with the rows for your result set ?DECLARE @Ayear INT??--訂單提交時間年 ?DECLARE @Amonth INT??--訂單提交時間月 ?DECLARE @Aday INT??--訂單提交時間日 ? ?DECLARE @BEGINday INT?--結算開始日 ?DECLARE @ENDday INT???? --結算截止日 ? ?DECLARE @BsettlementTime DATETIME;???? ----結算周期開始時間 ?DECLARE @EsettlementTime DATETIME;??? ----結算周期結束時間 ? ?DECLARE @NextYear INT???????????????? ----下一年 ?DECLARE @PreYear INT????? ----上一年 ?DECLARE @NextMonth INT????? ----下一月 ?DECLARE @PreMonth INT????? ----上一月 ? ?DECLARE @returnval INT???? --返回值 ? ?SET @Ayear = YEAR(@applyorderTime) ?SET @Amonth = MONTH(@applyorderTime) ?SET @Aday = DAY(@applyorderTime) ? ?SELECT @BEGINday = BeginDate ,@ENDday = ENDDate FROM Config_BillingCycle WHERE ModuleID=@ModuleID AND RegionID=@RegionID AND isvalid=1 ??IF(@Aday<=@BEGINday? AND @Aday<=@BEGINday )? --上月和本月(都小于) ??BEGIN ???SET @PreMonth =@Amonth-1 ???IF(@PreMonth<=0)---1月份的情況 ???BEGIN ????SET @PreYear = @Ayear -1 ????SET @BsettlementTime = CONVERT(VARCHAR(4),@PreYear)+'-12'+'-'+CONVERT(VARCHAR(4),@BEGINday) ????SET @EsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-01'+'-'+CONVERT(VARCHAR(4),@ENDday)? ???END ???ELSE ???BEGIN ????SET @BsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-'+CONVERT(VARCHAR(4),@PreMonth)+'-'+CONVERT(VARCHAR(4),@BEGINday) ????SET @EsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-'+CONVERT(VARCHAR(4),@Amonth)+'-'+CONVERT(VARCHAR(4),@ENDday) ???END ??END ??IF(@Aday>=@BEGINday? AND @Aday>=@BEGINday )? --本月和下月(大于) ??BEGIN ???SET @NextMonth =@Amonth+1 ???IF(@NextMonth >=13)----12月份的情況 ???BEGIN ????SET @NextYear = @Ayear +1 ????SET @BsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-12'+'-'+CONVERT(VARCHAR(4),@BEGINday) ????SET @EsettlementTime = CONVERT(VARCHAR(4),@NextYear)+'-01'+'-'+CONVERT(VARCHAR(4),@ENDday) ???END ???ELSE ???BEGIN ????SET @BsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-'+CONVERT(VARCHAR(4),@Amonth)+'-'+CONVERT(VARCHAR(4),@BEGINday) ????SET @EsettlementTime = CONVERT(VARCHAR(4),@Ayear)+'-'+CONVERT(VARCHAR(4),@NextMonth)+'-'+CONVERT(VARCHAR(4),@ENDday)?? ???END ??END ??IF(@BsettlementTime <=GETDATE() AND @EsettlementTime >= GETDATE()) ???BEGIN ????SET @returnval = 0 ???END ???ELSE ???BEGIN ????SET @returnval = 1 ???END? ?INSERT @table SELECT @BsettlementTime,@EsettlementTime,@returnval ?RETURN END GO |