I was recently asked a very simple, but very important question: “What is the impact of setting SET ANSI_WARNING OFF in a stored procedure?”
My immediate reaction was to understand why the team was trying to set ANSI_WARNINGS to OFF because setting ANSI_WARNINGS to OFF can have an impact on the data quality and system behaviour. This article demonstrates how setting ANSI_WARNINGS of OFF impacts system behaviour.
What is the SET option ANSI_WARNINGS?The ANSI_WARNINGS controls the standard ISO behavior of the SQL Server database engine for various error conditions. When ANSI_WARNINGS is set to ON, the engine follows the standard ISO behavior for the following situations:
Encountering a NULL value during an aggregation operation Encountering a Divide by Zero error String truncationWhen ANSI_WARNINGS is OFF, the engine follows a non-standard behavior, which reduces data quality and depending upon your business context, may generate bad data.
The examples below demonstrate the standard and non-standard ISO behavior when ANSI_WARNINGS is ON v/s OFF for each of the scenarios mentioned above.
Null value is eliminated by an aggregate or other SET operationIn our system, most aggregates are performed over revenue values, which would rarely be NULL. One would either have a 0, signifying no revenue, or some value (negative or positive), signifying a balance amount.
However, when aggregations (SUM, AVG, MAX, MIN, STDEV, STDEVP, VAR, VARP, or COUNT) are performed over columns that may contain NULLs (lap timings for example) a warning will be returned. This code sample demonstrates the issue.
In this example:
Confirm that ANSI_WARNINGS are set to ON by using the @@OPTIONS configuration function Generate a test scenario wherein we have race data (LapNumber and LapTime) from some athletes. In cases where the athlete was not able to complete the lap, the LapTime would be NULL We try to perform a simple aggregation to find the minimum lap time, i.e. "Fastest Lap Time" USE tempdb;GO
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
GO
--Confirm that the option SET ANSI_WARNINGS is ON
IF (@@OPTIONS & 8) > 0
BEGIN
PRINT 'SET ANSI_WARNINGS is ON.';
END
GO
DECLARE @lapTiming TABLE (LapNumber INT NOT NULL IDENTITY(1,1),
RunnerId INT NOT NULL,
LapTime DECIMAL(19,4) NULL
);
INSERT INTO @lapTiming (RunnerId, LapTime)
VALUES (1, '1.10'),
(2, '1.12'),
(3, NULL ), --Assume this player is DNF
(4, '1.05');
SELECT MIN(lt.LapTime) AS FastestLap
FROM @lapTiming AS lt;
/*******************
RESULTS
--------------------
SET ANSI_WARNINGS is ON.
Warning: Null value is eliminated by an aggregate or other SET operation.
*******************/
GO
The results are shown below. While the aggregation worked, we also get a warning in the "Messages" tab of SSMS:


The warning simply notifies the user that the rows with NULL values were ignored when performing the aggregation, which should be expected because one cannot perform any mathematical operation on an unknown value (NULL indicates an unknown value). Therefore, this behavior is not an error, but a note that the system is actually working as expected.
However, when ANSI_WARNINGS is set to OFF, no warning is returned and SQL Server silently ignores the rows with NULL values. Here is the same code with the ANSI_WARNINGS set to OFF.
USE tempdb;GO
SET NOCOUNT ON;
SET ANSI_WARNINGS OFF;
GO
--Confirm that the option SET ANSI_WARNINGS is ON
IF (@@OPTIONS & 8) > 0
BEGIN
PRINT 'SET ANSI_WARNINGS is ON.';
END
GO
DECLARE @lapTiming TABLE (LapNumber INT NOT NULL IDENTITY(1,1),
RunnerId INT NOT NULL,
LapTime DECIMAL(19,4) NULL
);
INSERT INTO @lapTiming (RunnerId, LapTime)
VALUES (1, '1.10'),
(2, '1.12'),
(3, NULL ), --Assume this player is DNF
(4, '1.05');
SELECT MIN(lt.LapTime) AS FastestLap
FROM @lapTiming AS lt;
GO
The results and Message tabs are shown here.


This is especially confusing when performing a COUNT on a column with NULL values and the result does not match the number of rows available in the result set. This is because the rows with NULL values would have been eliminated from the aggregation without any notification of the elimination.
Conclusion #1:As can be seen from the example above, setting ANSI_WARNINGS OFF can eliminate warnings being logged if the aggregations are being done as part of a nightly job. However, it may cause confusion when validating the results of the aggregation.
Msg 8134 Divide by zero error encounteredTypically, a division by zero error is a classic indication of bad data. One would expect that the offending statement in the batch is terminated and that the transaction encountering the divide by zero error is rolled back.
This is the ISO standard behavior enforced when both ARITHABORT and ANSI_WARNINGS are set to ON. ARITHABORT ON terminates the statement as soon as the divide by zero error is encountered and ANSI_WARNINGS ON takes care of reporting the error to the client application.
We can see this in the code sample below which performs a simple division operation on a set of values. One of the divisors is a zero and will result in a divide by zero error. When the error is encountered, the entire transaction will be rolled back because ANSI_WARNINGS is set to ON and the client application will be notified accordingly.
USE tempdb;GO
SET NOCOUNT ON;
SET ANSI_WARNINGS ON; --Setting this to ON will automatically turn ARITHABORT to ON
GO
--Confirm that the option SET ANSI_WARNINGS is ON
IF (@@OPTIONS & 8) > 0
BEGIN
PRINT 'SET ANSI_WARNINGS is ON.';
END
GO
IF OBJECT_ID('#mathOps','U') IS NOT NULL
BEGIN
DROP TABLE #mathOps;
END
GO
CREATE TABLE #mathOps (RowId INT NOT NULL IDENTITY(1,1),
OpA DECIMAL(19,4) NULL,
OpB DECIMAL(19,4) NULL,
MathResult DECIMAL(19,4) NULL
);
INSERT INTO #mathOps (OpA, OpB)
VALUES (1.0, 2.0),
(1.0, 3.0),
(1.0, 0.0),
(1.0, 33.0);
GO
UPDATE mops
SET mops.MathResult = (mops.OpA/mops.OpB)
FROM #mathOps AS mops
GO
SELECT mops.RowId,
mops.OpA,
mops.OpB,
mops.MathResult
FROM #mathOps AS mops;
GO
The screenshot below confirms that none of the records were updated (the statement was indeed terminated and that transaction rolled back) with the following error message being returned:
SET ANSI_WARNINGS is ON.<br /> <code>Msg 8134, Level 16, State 1, Line 36<br /> Divide by zero error encountered.</code><br /> The statement has been terminated.

However, when both ARITHABORT and ANSI_WARNINGS are OFF, the statement is not aborted. Instead of a rollback, what we see is that when a divide by zero is encountered, the output of the division is a NULL, i.e. unknown.
The setting of ARITHABORT to OFF prevents the statement from rolling back and the ANSI_WARNINGS