1

I have about 15 existing stored procedures that I modified to add logging. All of them are working except this one.

When Visual Studio attempts to execute the query, it displays the following error:

System.Data.SqlClient.SqlException: 'Cannot insert the value NULL into column 'Reason', table 'Claims.dbo.History'; column does not allow nulls. INSERT fails.

In the SQL below, I do not see how the 'Reason' field could be null.

Microsoft SQL Server 2016 (SP3-GDR) (KB5046063) - 13.0.6450.1 (X64) Sep 27 2024 19:17:51 Copyright (c) Microsoft Corporation Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2012 R2 Standard 6.3 <X64> (Build 9600: ) (Hypervisor)

What have I missed?

USE [CCC]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[spVendor_Active_Update] (
    @VendorID   int,
    @Active         bit,
    @sUserLogin     varchar(100) = ''
) AS

DECLARE @oldActive bit, @summary varchar(max);

SELECT @oldActive = v.IsActive
FROM CCC.dbo.Vendor v
WHERE v.idVendor = @VendorID

UPDATE  CCC.dbo.Vendor
SET
    IsActive =@Active
WHERE
    idVendor = @VendorID

SET @summary = 'CCC.dbo.spVendor_Active_Update: Vendor.IsActive (old): [' + Convert(varchar(10), @oldActive) + ']; (new): [' + Convert(varchar(10), @Active) + '];';

-- Log event
INSERT INTO Claims.dbo.[History]
(
    [UserID],
    [Time],
    [Reason]
)
VALUES
(
    @sUserLogin,
    GETDATE(),
    @summary
)

The record in 'Vendor' does get updated, but the INSERT into 'History' fails.

What have I missed?

I converted values for @oldActive and @Active to varchar(10), which should be more than plenty. A single 'char' should be fine, but I want to make sure.

5
  • 2
    Seems likely that one or both of the @Active or @oldActive bit values are null. When CONCAT_NULL_YIELDS_NULL is in effect concatenating string segments where any one of them was null will be a null result. Commented Oct 10, 2024 at 21:39
  • 2
    Debugging is an essential programmer's skill. Have you tried to SELECT @Summary or PRINT @Summary before running your last insert?
    – Eric
    Commented Oct 10, 2024 at 21:41
  • @Eric - I don't debug much in SSMS. Where does SELECT @Summary or PRINT @Summary output to? I make the calls from within the Visual Studio code.
    – jp2code
    Commented Oct 10, 2024 at 21:45
  • 2
    It's a stored procedure so you debug it in SSMS. Once the sp is working properly, then you use it in your code.
    – Eric
    Commented Oct 10, 2024 at 21:47
  • 4
    And use CONCAT vs + for string concatenation. It handles type conversion and null-to-empty string conversion for you. Commented Oct 10, 2024 at 23:33

2 Answers 2

1

Clearly somewhere there is a null value. Looking back through the code, either @Active was passed as null, or there was no row so @oldActive is null. Both of these conditions should have been handled properly. The former can be fixed with ISNULL, the latter you should just throw an error as the UPDATE never worked.

Also you can combine your SELECT and UPDATE into a single statement.

CREATE OR ALTER PROCEDURE dbo.spVendor_Active_Update (
    @VendorID   int,
    @Active         bit = 0,
    @sUserLogin     varchar(100) = ''
) AS

SET @Active = ISNULL(@Active, 0);

DECLARE @oldActive bit, @summary varchar(max);

UPDATE CCC.dbo.Vendor
SET
    @oldActive = IsActive
    IsActive   = @Active
WHERE
    idVendor = @VendorID;

IF @@ROWCOUNT = 0
    THROW 50001, N'No vendor found', 1;

SET @summary = 'CCC.dbo.spVendor_Active_Update: Vendor.IsActive (old): [' + Convert(varchar(10), @oldActive) + ']; (new): [' + Convert(varchar(10), @Active) + '];';

INSERT INTO Claims.dbo.History
(
    UserID,
    Time,
    Reason
)
VALUES
(
    @sUserLogin,
    GETDATE(),
    @summary
);
0

This was answered earlier today in the comments that are now missing:

SET @summary = 'CCC.dbo.spVendor_Active_Update: Vendor.IsActive (old): [' + Convert(varchar(10), ISNULL(@oldActive, 0)) + ']; (new): [' + Convert(varchar(10), ISNULL(@Active, 0)) + '];';

Adding ISNULL was necessary to convert null bit values to varchar.

1
  • 7
    The fix will work, but the description why is wrong. You can convert the bit to varchar without that, but bit values in SQL have three states rather than two: 1, 0, or NULL. In the case the bit was NULL, the conversion is a NULL string unless you wrap it with something like ISNULL(), COALESCE(), or CASE. And when you then concatenate a NULL string with a non-NULL string, you get... a NULL string. Remember: NULL does not mean "empty".; it means you don't know. And when you concatenate the known with the unknown, the result is also unknown. Commented Oct 10, 2024 at 21:43

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.