Sql函数问题“函数中包含的最后一个语句必须是return语句”

时间:2014-11-18 12:45:53

标签: sql sql-server

在下面的SQL函数中,我必须根据条件返回值,但它会抛出错误。

  

"函数中包含的最后一个语句必须是return   。声明"

请帮助我克服这个问题。

ALTER FUNCTION [dbo].[GetBatchReleaseQuantity]   
(
@i_LocationID VARCHAR(50),
    @i_ProductID INT,
    @i_StartDate VARCHAR(50),  
    @i_EndDate VARCHAR(50),  
    @i_ProductInFlow int
)  
RETURNS numeric(18,3)  
 --WITH ENCRYPTION     
AS  
BEGIN  

  IF (@i_ProductInFlow ='2')
  BEGIN

  RETURN (SElECT ISNULL( SUM( BatchReleaseQuantity),0.00)  From  BatchReleaseDetails BRD
  LEFT OUTER JOIN BatchRelease BR ON BR.BatchReleaseID=BRD.BatchReleaseID
  Where  ProductId=@i_ProductID  AND LocationID=@i_LocationID AND BRD.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND BRD.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59'))
  END
  ELSE
  BEGIN
  RETURN(SElECT ISNULL( SUM( AcceptedQuantity),0.00)  From  GoodsReceivedNoteDetail GRND
  LEFT OUTER JOIN GoodsReceivedNote GRN ON GRN.LocationID=@i_LocationID
  Where  ProductId=@i_ProductID  AND GRN.LocationID=@i_LocationID AND GRND.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND GRND.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59'))
  END 
END

3 个答案:

答案 0 :(得分:3)

函数期望在最后一行返回。 只需通过将结果赋值给变量@nReturn并在最后一行返回它来修改函数。

create FUNCTION [dbo].[GetBatchReleaseQuantity]   
(
@i_LocationID VARCHAR(50),
    @i_ProductID INT,
    @i_StartDate VARCHAR(50),  
    @i_EndDate VARCHAR(50),  
    @i_ProductInFlow int
)  
RETURNS numeric(18,3)  
 --WITH ENCRYPTION     
AS  
BEGIN  

 DECLARE @nReturn numeric(18,3)

  IF (@i_ProductInFlow ='2')
  BEGIN

  SElECT @nReturn = ISNULL( SUM( BatchReleaseQuantity),0.00)  From  BatchReleaseDetails BRD
  LEFT OUTER JOIN BatchRelease BR ON BR.BatchReleaseID=BRD.BatchReleaseID
  Where  ProductId=@i_ProductID  AND LocationID=@i_LocationID AND BRD.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND BRD.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59')
  END
  ELSE
  BEGIN
  SElECT @nReturn = ISNULL( SUM( AcceptedQuantity),0.00)  From  GoodsReceivedNoteDetail GRND
  LEFT OUTER JOIN GoodsReceivedNote GRN ON GRN.LocationID=@i_LocationID
  Where  ProductId=@i_ProductID  AND GRN.LocationID=@i_LocationID AND GRND.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND GRND.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59')
  END 

  RETURN  @nReturn
END

答案 1 :(得分:2)

如错误所示,最后一个语句必须是return语句。与其他语言不同,编译期间不会检查IF/ELSE语句的流,因此SQL Server不知道其中一个分支是必需的(即使ELSE)。由于未检查此项,因此无法知道函数是否将返回值,除非最后一个语句是return语句。即使像这样的简单函数也会失败:

CREATE FUNCTION dbo.FlowTest()
RETURNS INT
AS
BEGIN
    IF 1 = 1
    BEGIN
        RETURN 1;
    END
    ELSE
    BEGIN
        RETURN 0;
    END
END

解决方案是删除ELSE

CREATE FUNCTION dbo.FlowTest()
RETURNS INT
AS
BEGIN
    IF 1 = 1
    BEGIN
        RETURN 1;
    END
    -- ELSE REMOVED
    RETURN 0;

END

如果到达第一个RETURN,该函数将停止执行,因此无论如何都不需要ELSE

所以你的功能将成为:

ALTER FUNCTION [dbo].[GetBatchReleaseQuantity]   
(
@i_LocationID VARCHAR(50),
    @i_ProductID INT,
    @i_StartDate VARCHAR(50),  
    @i_EndDate VARCHAR(50),  
    @i_ProductInFlow int
)  
RETURNS numeric(18,3)  
 --WITH ENCRYPTION     
AS  
BEGIN  

  IF (@i_ProductInFlow ='2')
  BEGIN

    RETURN (SElECT  ISNULL( SUM( BatchReleaseQuantity),0.00)  
            FROM    BatchReleaseDetails BRD
                    LEFT OUTER JOIN BatchRelease BR 
                        ON BR.BatchReleaseID=BRD.BatchReleaseID
            WHERE   ProductId = @i_ProductID  
            AND     LocationID = @i_LocationID 
            AND     BRD.CreatedOn >= CONVERT(DATETIME, @i_StartDate+' 00:00:00') 
            AND     BRD.CreatedOn <= CONVERT(DATETIME,@i_EndDate + ' 23:59:59')
        )
  END

  RETURN (  SELECT  ISNULL( SUM( AcceptedQuantity),0.00)  
            FROM    GoodsReceivedNoteDetail GRND
                    LEFT OUTER JOIN GoodsReceivedNote GRN 
                        ON GRN.LocationID=@i_LocationID
            WHERE   ProductId = @i_ProductID  
            AND     GRN.LocationID = @i_LocationID 
            AND     GRND.CreatedOn >= CONVERT(DATETIME, @i_StartDate+' 00:00:00') 
            AND     GRND.CreatedOn <= CONVERT(DATETIME, @i_EndDate+' 23:59:59')
        )
  END 

END

我无法看到该功能如何表现良好,以及为什么你传递日期作为varchar是超出我的。你不关心23:59:59到午夜之间创造的东西吗?

我倾向于将其重构为内联表值函数,并正确使用日期,例如。

CREATE FUNCTION [dbo].[GetBatchReleaseQuantityTVP]   
(
    @i_LocationID VARCHAR(50),
    @i_ProductID INT,
    @i_StartDate DATE,  
    @i_EndDate DATE,  
    @i_ProductInFlow int
)  
RETURNS TABLE
 --WITH ENCRYPTION     
AS  
RETURN 
(   SElECT  ReturnValue = ISNULL( SUM( BatchReleaseQuantity),0.00)  
    FROM    BatchReleaseDetails BRD
            LEFT OUTER JOIN BatchRelease BR 
                ON BR.BatchReleaseID=BRD.BatchReleaseID
    WHERE   ProductId = @i_ProductID  
    AND     LocationID = @i_LocationID 
    AND     BRD.CreatedOn >= @i_StartDate
    AND     BRD.CreatedOn < DATEADD(DAY, 1, @i_EndDate)
    AND     @i_ProductInFlow ='2'
    UNION ALL
    SELECT  ISNULL(SUM( AcceptedQuantity),0.00)  
    FROM    GoodsReceivedNoteDetail GRND
            LEFT OUTER JOIN GoodsReceivedNote GRN 
                ON GRN.LocationID=@i_LocationID
    WHERE   ProductId = @i_ProductID  
    AND     GRN.LocationID = @i_LocationID 
    AND     GRND.CreatedOn >= @i_StartDate
    AND     GRND.CreatedOn < DATEADD(DAY, 1, @i_EndDate)
    AND     ISNULL(@i_ProductInFlow, '') != '2'
);

然后,只要您拨打dbo.GetBatchReleaseQuantity(...),只需致电(SELECT ReturnValue FROM dbo.GetBatchReleaseQuantityTVP(...))即可。这将显着改善,并且还可以避免人们将无效日期传递给varchar参数。

答案 2 :(得分:1)

您无法像在C ++或C#中那样从SQL函数返回。在FUNCTION块的末尾应该只有一个return语句:

所以只需将返回值放在局部变量中,并在函数末尾使用RETURN语句:

ALTER FUNCTION [dbo].[GetBatchReleaseQuantity]   
(
@i_LocationID VARCHAR(50),
    @i_ProductID INT,
    @i_StartDate VARCHAR(50),  
    @i_EndDate VARCHAR(50),  
    @i_ProductInFlow int
)  
RETURNS numeric(18,3)  
 --WITH ENCRYPTION     
AS  
BEGIN  


  DECLARE @retval NUMERIC(18, 3)    
  IF (@i_ProductInFlow ='2')
  BEGIN

  SElECT @retval = ISNULL( SUM( BatchReleaseQuantity),0.00)  From  BatchReleaseDetails BRD
  LEFT OUTER JOIN BatchRelease BR ON BR.BatchReleaseID=BRD.BatchReleaseID
  Where  ProductId=@i_ProductID  AND LocationID=@i_LocationID AND BRD.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND BRD.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59')
  END
  ELSE
  BEGIN
  SElECT @retval =  ISNULL( SUM( AcceptedQuantity),0.00)  From  GoodsReceivedNoteDetail GRND
  LEFT OUTER JOIN GoodsReceivedNote GRN ON GRN.LocationID=@i_LocationID
  Where  ProductId=@i_ProductID  AND GRN.LocationID=@i_LocationID AND GRND.CreatedOn>=convert(datetime,@i_StartDate+' 00:00:00') AND GRND.CreatedOn<=convert(datetime,@i_EndDate+' 23:59:59')
  END 

  RETURN @retval
END