Skip to content

SQL Server Error Messages - Msg 181

Error Message

Server: Msg 181, Level 15, State 1,
Procedure <Procedure Name>, Line 1
Cannot use the OUTPUT option in a DECLARE, CREATE AGGREGATE or CREATE FUNCTION statement.

Causes

The OUTPUT (or OUT for short) parameter option indicates that a parameter is an output parameter in a stored procedure. With this option specified on a parameter, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits.

The OUTPUT option can only be specified in a parameter to a stored procedure. It cannot be specified as an option to a local variable declared using the DECLARE statement. Depending on the version of SQL Server used, the following DECLARE statement with the OUTPUT option will generate an error with different error messages.

DECLARE @RowCount INT OUTPUT

Using SQL Server 2000, the following message will be received:

Msg 181, Level 15, State 1, Line 1
Cannot use the OUTPUT option in a DECLARE statement.

On the other hand, using SQL Server 2005, the following message will be received for the same DECLARE statement with the OUTPUT option:

Msg 181, Level 15, State 1, Line 1
Cannot use the OUTPUT option in a DECLARE or CREATE FUNCTION statement.

Using SQL Server 2008, a totally different error message will be generated:

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'OUTPUT'.

Based on the error message received from SQL Server 2000 and SQL Server 2005, the OUTPUT option cannot also be specified in the parameters of a user-defined function. To illustrate on how this error can be generated from a user-defined function, given the following table structure:

CREATE TABLE [dbo].[Sales] (
      [SalesID]               INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
      [SalesPersonID]         INT,
      [ProductID]             INT,
      [UnitCount]             INT,
      [SalesAmount]           MONEY,
      [SalesDate]             DATETIME
) 
GO

The following user-defined function, which returns the average sales amount for a given sales person (if provided) and for a given product (if provided) as well as the total sales amount and total units sold as output parameters, will generate a bunch of errors:

CREATE FUNCTION [dbo].[ufn_GetSales] (
      @SalesPersonID          INT,
      @ProductID              INT,
      @TotalCount             INT OUTPUT,
      @TotalAmount            MONEY OUTPUT )
RETURNS MONEY
AS
BEGIN
    DECLARE @AverageSales  MONEY

    SELECT @TotalCount = SUM([UnitCount]),
           @TotalAmount = SUM([SalesAmount])
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    SET @AverageSales = @TotalAmount / NULLIF(@TotalCount, 0)

    RETURN @AverageSales
END 
GO
Msg 181, Level 15, State 1, Procedure ufn_GetSales, Line 4
Cannot use the OUTPUT option in a DECLARE, CREATE AGGREGATE or CREATE FUNCTION statement.
Msg 137, Level 15, State 1, Procedure ufn_GetSales, Line 11
Must declare the scalar variable "@TotalCount".
Msg 137, Level 15, State 2, Procedure ufn_GetSales, Line 17
Must declare the scalar variable "@TotalAmount".
Msg 178, Level 15, State 1, Procedure ufn_GetSales, Line 19
A RETURN statement with a return value cannot be used in this context.

Solution / Work Around

To avoid this error in a DECLARE statement make sure that the OUTPUT option is not specified. Only specify the OUTPUT option in a parameter of a stored procedure.

In the case the OUTPUT option in a user-defined function parameter, there are different ways of working around this. Given that there are 3 different outputs needed from the user-defined function shown earlier, the first option is to create 3 separate user-defined functions, one returning the total sales amount, another returning the total sales count and lastly another one returning the average sales amount.

CREATE FUNCTION [dbo].[ufn_GetTotalSalesAmount] (
    @SalesPersonID    INT,
    @ProductID        INT
)
RETURNS MONEY
AS
BEGIN
    DECLARE @TotalAmount    MONEY

    SET @TotalAmount = 0.00
    SELECT @TotalAmount = SUM([SalesAmount])
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    RETURN @TotalAmount
END
GO
CREATE FUNCTION [dbo].[ufn_GetTotalSalesCount] (
    @SalesPersonID    INT,
    @ProductID        INT
)
RETURNS INT
AS
BEGIN
    DECLARE @TotalCount     INT

    SET @TotalCount = 0
    SELECT @TotalCount = SUM([UnitCount])
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    RETURN @TotalCount
END
GO
CREATE FUNCTION [dbo].[ufn_GetAverageSalesAmount] (
    @SalesPersonID    INT,
    @ProductID        INT
)
RETURNS MONEY
AS
BEGIN
    DECLARE @AverageSales   MONEY

    SET @AverageSales = 0.00
    SELECT @AverageSales = SUM([SalesAmount]) / NULLIF(SUM([UnitCount]), 0)
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    RETURN @AverageSales
END
GO

The disadvantage of using 3 different user-defined functions is that it will perform 3 separate SELECT statements to get the three different output values. To overcome this disadvantage, the second option that can be done is to use a stored procedure instead of a user-defined function.

CREATE PROCEDURE [dbo].[usp_GetSalesValues]
    @SalesPersonID    INT,
    @ProductID        INT,
    @TotalAmount      MONEY OUTPUT,
    @TotalCount       INT OUTPUT,
    @AverageAmount    MONEY OUTPUT
AS
    DECLARE @AverageSales  MONEY

    SELECT @TotalCount = SUM([UnitCount]),
           @TotalAmount = SUM([SalesAmount])
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    SET @AverageSales = @TotalAmount / NULLIF(@TotalCount, 0)
GO

If it’s a user-defined function that is really required to be used and not a stored procedure, then instead of using a scalar function, a multi-statement table-valued function should be used instead.

CREATE FUNCTION [dbo].[ufn_GetSalesValues] (
    @SalesPersonID    INT,
    @ProductID        INT
) RETURNS @SalesValues TABLE (
    [TotalAmount]      MONEY,
    [TotalCount]       INT,
    [AverageAmount]    MONEY
)
AS
BEGIN
    INSERT INTO @SalesValues ( [TotalAmount], [TotalCount], [AverageAmount] )
    SELECT SUM([SalesAmount]), SUM([UnitCount]),
           SUM([SalesAmount]) / NULLIF(SUM([UnitCount]), 0)
    FROM [dbo].[Sales]
    WHERE ([SalesPersonID] = @SalesPersonID OR @SalesPersonID IS NULL) AND
          ([ProductID] = @ProductID OR @ProductID IS NULL)

    RETURN
END
GO