sql >> データベース >  >> RDS >> Sqlserver

SQL関数の問題関数に含まれる最後のステートメントはreturnステートメントである必要があります

    エラーが示すように、最後のステートメントはreturnステートメントである必要があります。他のいくつかの言語とは異なり、IF/ELSEのフロー ステートメントはコンパイル中にチェックされないため、SQL Serverはブランチの1つが必須であることを認識しません(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 [email protected]_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 [email protected]_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パラメータに無効な日付が渡されるのを防ぐことができます。



    1. レコードを削除しないステートメントの削除

    2. mysql(i)_real_escape_string、信頼しても安全ですか?

    3. SQL Serverの名前からオブジェクトのIDを取得します:OBJECT_ID()

    4. ORA-01843は有効な月ではありません-日付の比較