Although I send the parameter I get "Can not insert NULL value..." - sql

I am developing an ADO.NET application. At some point in the DAL I call a stored-procedure named "CREATE_CUSTOMER". Although I set the SHORT_NAME field I still get the
"Msg 515, Level 16, State 2, Procedure CREATE_CUSTOMER, Line 29
Cannot insert the value NULL into column 'SHORT_NAME', table 'MYDB.app.CUSTOMER';
column does not allow nulls. INSERT fails." error.
When I inspect the query with the SQL profiler I get the following SQL runs on the server. As I Copy&Paste it to a new Query Window I still get the same error.
Do I miss something?
declare #p16 int
set #p16=NULL
exec sp_executesql N'[app].[CREATE_CUSTOMER]',
N'#SHORT_NAME nvarchar(11),
#MAIL_NAME nvarchar(18),
#MT_SALESPERSON_ID int,
#CREDIT_LIMIT decimal(1,0),
#CREDIT_LIMIT_CURRENCY_ID int,
#PAYMENT_TYPE_ID int,
#SALES_TERM_ID int,
#FREE_STORAGE_DAY_ID int,
#RISK_GROUP_ID int,
#SECTOR_ID int,
#OCCUPATION_ID int,
#STORAGE_FEE_ID int,
#STATUS smallint,
#IDENTITY int output',
#SHORT_NAME=N'NEW Corp',
#MAIL_NAME=N'NEW Corporation',
#MT_SALESPERSON_ID=3,
#CREDIT_LIMIT=0,
#CREDIT_LIMIT_CURRENCY_ID=1,
#PAYMENT_TYPE_ID=4,
#SALES_TERM_ID=7,
#FREE_STORAGE_DAY_ID=6,
#RISK_GROUP_ID=3,
#SECTOR_ID=13,
#OCCUPATION_ID=16,
#STORAGE_FEE_ID=6,
#STATUS=0,
#IDENTITY=#p16 output
select #p16
And my Stored Procedure is as follows :
CREATE PROCEDURE [app].[CREATE_CUSTOMER]
#SHORT_NAME varchar(250) = NULL,
#MAIL_NAME varchar(500) = NULL,
#MT_SALESPERSON_ID int = NULL,
#CREDIT_LIMIT decimal(18,2) = NULL,
#CREDIT_LIMIT_CURRENCY_ID int = NULL,
#PAYMENT_TYPE_ID int = NULL,
#SALES_TERM_ID int = NULL,
#FREE_STORAGE_DAY_ID int = NULL,
#RISK_GROUP_ID int = NULL,
#SECTOR_ID int = NULL,
#OCCUPATION_ID int = NULL,
#STORAGE_FEE_ID int = NULL,
#STATUS tinyint = NULL,
#IDENTITY INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [app].[CUSTOMER]
([SHORT_NAME],
[MAIL_NAME],
[MT_SALESPERSON_ID],
[CREDIT_LIMIT],
[CREDIT_LIMIT_CURRENCY_ID],
[PAYMENT_TYPE_ID],
[SALES_TERM_ID],
[FREE_STORAGE_DAY_ID],
[RISK_GROUP_ID],
[SECTOR_ID],
[OCCUPATION_ID],
[STORAGE_FEE_ID],
[STATUS],
[CREATE_DATE],
[CREATE_USERID])
VALUES
(#SHORT_NAME,
#MAIL_NAME,
#MT_SALESPERSON_ID,
#CREDIT_LIMIT,
#CREDIT_LIMIT_CURRENCY_ID,
#PAYMENT_TYPE_ID,
#SALES_TERM_ID,
#FREE_STORAGE_DAY_ID,
#RISK_GROUP_ID,
#SECTOR_ID,
#OCCUPATION_ID,
#STORAGE_FEE_ID,
#STATUS,
GETDATE(),
CONTEXT_INFO())
SELECT #IDENTITY = SCOPE_IDENTITY()
END
This SQL code is being generated by the ADO.NET. Actual C# code is :
private static ICustomer CreateCustomer(ICustomer customer, int contextUserId)
{
try
{
string sql = "[app].[CREATE_CUSTOMER]";
SqlConnection conn = null;
using (conn = GetConnection())
{
SetContextInfomationToConnection(conn, contextUserId);
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#SHORT_NAME", customer.ShortName);
cmd.Parameters.AddWithValue("#MAIL_NAME", customer.MailName);
cmd.Parameters.AddWithValue("#MT_SALESPERSON_ID", customer.SalesPersonId);
cmd.Parameters.AddWithValue("#CREDIT_LIMIT", customer.CreditLimit);
cmd.Parameters.AddWithValue("#CREDIT_LIMIT_CURRENCY_ID", customer.CreditLimitCurrencyId);
cmd.Parameters.AddWithValue("#PAYMENT_TYPE_ID", customer.PaymentTypeId);
cmd.Parameters.AddWithValue("#SALES_TERM_ID", customer.SalesTermId);
cmd.Parameters.AddWithValue("#FREE_STORAGE_DAY_ID", customer.FreeStorageDayId);
cmd.Parameters.AddWithValue("#RISK_GROUP_ID", customer.RiskGroupId);
cmd.Parameters.AddWithValue("#SECTOR_ID", customer.SectorId);
cmd.Parameters.AddWithValue("#OCCUPATION_ID", customer.OccupationId);
cmd.Parameters.AddWithValue("#STORAGE_FEE_ID", customer.StorageFeeId);
cmd.Parameters.AddWithValue("#STATUS", customer.Status);
SqlParameter prmNewId = new SqlParameter("#IDENTITY", SqlDbType.Int, 4);
prmNewId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prmNewId);
cmd.ExecuteNonQuery();
int id = prmNewId.Value != DBNull.Value ? (int)prmNewId.Value : -1;
if (id > 0)
{
customer.Id = id;
return customer;
}
else
{
throw new Exception("Can not insert customer record with Id generation");
}
}
}
catch (Exception ex)
{
throw;
}
}

Your code is the equivalent of doing this:
DECLARE #SHORT_NAME nvarchar(11) = N'NEW Corp';
...
EXEC [app].[CREATE_CUSTOMER];
You are just declaring the parameters, never actually passing them to the procedure invocation. Your code should be like this:
exec sp_executesql N'[app].[CREATE_CUSTOMER] #SHORT_NAME, #MAIL_NAME, ...',
N'#SHORT_NAME nvarchar(11),
#MAIL_NAME nvarchar(18),
...',
#SHORT_NAME=N'NEW Corp',
#MAIL_NAME=N'NEW Corporation',
...
You must not only declare the parameters you pass to the batch, you must also use them when you invoke the procedure.
When I inspect the query with the SQL profiler I get the following SQL runs on the server. As I Copy&Paste it to a new Query Window I still get the same error
This sounds suspiciously like you are using a SqlCommand but forgot to set the CommandType to Procedure. the default is Text and will behave exactly as you observed.

Do not assign null values to ur variable, try only with DECLARING it as bellow
DECLARE #SHORT_NAME varchar(250) ,
instead of
#SHORT_NAME varchar(250) = NULL,

Related

How do I retrieve scope identity with ExecuteNonQuery?

My project is using .NET Core 3.1 and I have my stored procedures executing in my repository class. I want to insert and return the scope identity(the id of the record that just inserted UserNumber) so I can use it for another stored proc within this same method. The problem I have here is that parameters[1].Value value is returning zero.
Here is an abbreviation of my stored proc:
ALTER PROCEDURE [dbo].[InsertUser]
#iUserNumber int OUTPUT,
As
INSERT dbo.tblUser (
CreatedBy
)
VALUES (#LoginUserId)
IF ##ERROR <> 0 GOTO ERRHANDLER
SET #UserNumber = SCOPE_IDENTITY() /** this is the primary Key **/
RETURN(#UserNumber)
Here is a sample of my repository
public int InsertUsers(int LoginUserId, int UserNumber)
{
SqlParameter[] parameters = new List<SqlParameter>()
{
_dbContext.CreateSqlParameter(StoredProcedureConstants.LoginUserId,SqlDbType.Int,LoginUserId.ToSafeInt()),
_dbContext.CreateSqlParameter(StoredProcedureConstants.UserNumber,SqlDbType.Int,UserNumber.ToSafeInt())
}.ToArray();
var intResult = _dbContext.ExecuteNonQuery(StoredProcedureConstants.InsertUsers, parameters);
var result2 = parameters[1].Value; //This comes back as zero
How do I assign the scope identity to result2?
Should be something like:
CREATE OR ALTER PROCEDURE [dbo].[InsertUser]
#LoginUserId int,
#iUserNumber int OUTPUT
As
INSERT dbo.tblUser (CreatedBy)
VALUES (#LoginUserId)
SET #iUserNumber = SCOPE_IDENTITY() /** this is the primary Key **/
and
SqlParameter[] parameters = new List<SqlParameter>()
{
_dbContext.CreateSqlParameter("#LoginuserId",SqlDbType.Int,LoginUserId),
_dbContext.CreateSqlParameter("#iUserNumber",SqlDbType.Int)
}.ToArray();
parameters[1].Direction = ParameterDirection.Output;
_dbContext.ExecuteNonQuery(StoredProcedureConstants.InsertUsers, parameters);
var result2 = parameters[1].Value;

SQL stored procedure call failed with index out of range

I am trying to execute a stored procedure in SQL Server from my java code. This stored procedure is used in some other language and it was working fine from long back. Now I need to integrate it in my java app. I have 15 columns in my table. When I tried this in my java code, its throwing
com.microsoft.sqlserver.jdbc.SQLServerException: The index 11 is out of range
I also see "Error: 0, SQLState: S1093"
My stored procedure
ALTER PROCEDURE [dbo].[user_input_sp]
#Username VARCHAR(10)=NULL,
#UserKey VARCHAR(50)=NULL,
#ReqTime DATETIME=null,
#ResTime DATETIME=null,
#Req TEXT=null,
#Res TEXT=null,
#condition TEXT=null,
#ID INT=null,
#Address VARCHAR(8000) = NULL,
#Task VARCHAR(50) = NULL,
#Direction INT=0,
#Seq INT=0,
#RR BIT=0,
#Correction VARCHAR(8) = NULL,
#PendingTrans VARCHAR(50) = NULL,
#ForwardID VARCHAR(50) = NULL,
#Command VARCHAR(50) = NULL
AS
DECLARE #TSqno int
#IF #Direction=0
BEGIN
EXECUTE Basp_NewKey 'web_log', #TSqno OUTPUT
Insert into cbscne dbo WebServiceLog( Order, US_Name, US_Key , US_ReqD, US_ResD, US_Req , US_Res, cond, ID ,Address, Task, Command)
values (#TSqno, #Username, #UserKey, #ReqTime, #ResTime, #Req ,#Res, #condition, #ID ,#Address, #Task ,#Command)
END
.......
My java code
public vold addWebServiceLogRequest(UserInput cd){
sessionFactory = sqlServerEMFactory.unwrap(SessionFactory.class);
Session sessionForSave = sessionFactory.openSession();
sessionForSave.beginTransaction();
sessionForSave.doReturningWork(connection-> {
try(CallableStatement cstmt = connection.prepareCall("{call user_input_sp(?,?,?,?,?,?,?,?,?)}")) {
cstmt.setInt("indicator", 0);
cstmt.setString("Username",cd.getInterfaceName());
cstmt.setInt("User_code",cd.getCaseId());
cstmt.setTimestamp("RetrieveDate",cd.getRequestDate());
cstmt.setTimestamp("ReturnDate",cd.getResponseDate());
cstmt.setString("Req",cd.getRequestxml());
cstmt.setString("Res",cd.getResponsexml());
cstmt.setString("Task",cd.getTask());
cstmt.setString("flow",null);
cstmt.execute();
cstmt.close();
connection.close();
return null;
}
});
}

Why ##rowcount returns 0 when more than 1 user access store procedure for insertion

i am using asp.net, i am calling insertion store procedure whihc works fine until one person is inserting but throw error when more than 1 person simultaneously inserts records i.e. ##RowCount stores 0 and returns 0 to application.
USE [CPOCMS]
GO
/** Object: StoredProcedure [dbo].[InsertComplaints] Script Date: 9/24/2014 11:56:13 AM **/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[InsertComplaints]
#ComplaintCode varchar(50),
#ComplaintType_ID smallint,
#RecievingMode_ID smallint,
#Subject varchar(100),
#ComplainantID smallint,
#District_ID smallint,
#AddressedTo varchar(50),
#DiaryNo varchar(50),
#User_ID int,
#Status_ID smallint,
#RecievedDate smalldatetime,
#IGRemarks varchar(MAX) = null,
#PsoRemarks varchar(MAX) =null,
#FinalDecision varchar(250)=null,
#AgainstDist_ID smallint,
#HomePS_ID smallint,
#AgainstPS_ID smallint,
#Name varchar(75),
#DesigID int,
#ForwardedBy smallint,
#SMS_ID int = 0,
#result bit output,
#ID int output
AS
BEGIN
Begin Try
insert into dbo.Complaints
values (
#ComplaintCode,
#ComplaintType_ID,
#RecievingMode_ID ,
#Subject,
#ComplainantID ,
#District_ID ,
#AddressedTo ,
#DiaryNo,
#User_ID,
#Status_ID,
#RecievedDate,
#IGRemarks,
#PsoRemarks,
#FinalDecision,
#AgainstDist_ID,
#HomePS_ID,
#AgainstPS_ID,
#Name ,
#DesigID,
#ForwardedBy,
#SMS_ID
)
Set #result = ##ROWCOUNT
Select #ID= Ident_Current('dbo.Complaints')
End Try
Begin Catch
Set #result=0
End Catch
END
in sql it shows ##Rowcount = 0 and in asp.net it returns #result=0 , why ?
cmd.ExecuteNonQuery();
Boolean Result = Convert.ToBoolean(pResult.Value);
if (Result)
{
int i = Convert.ToInt32(pID.Value);
return i;
}
else
{
return 0;
}
Note: i have removed unnecessary code.

Can't call stored procedure without specifying supposedly optional parameter

I'm trying to call a stored procedure with several required and several optional parameters. Before I came along, the beginning of the procedure scripted out like this:
USE [MYDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_GetStudents]
(
#SortOrder varchar(50),
#SortColumn varchar(150),
#SortLetter varchar(10),
#Status varchar(250),
#PageIndex int,
#PageSize int,
#User_ID int,
#Reference_No varchar(50) = NULL,
#First_Name varchar(50) = NULL,
#Middle_Name varchar(50) = NULL,
#Last_Name varchar(50) = NULL
)
As
BEGIN
-- other stuff here
Everything seems to work fine. Then I added another parameter to the end:
USE [MYDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_GetStudents]
(
#SortOrder varchar(50),
#SortColumn varchar(150),
#SortLetter varchar(10),
#Status varchar(250),
#PageIndex int,
#PageSize int,
#User_ID int,
#Reference_No varchar(50) = NULL,
#First_Name varchar(50) = NULL,
#Middle_Name varchar(50) = NULL,
#Last_Name varchar(50) = NULL,
#ContextID int = NULL
)
As
BEGIN
-- other stuff here
and now it's broken. When I use ADO.NET to call the stored proc by setting up a command object with parameters, it throws an exception because I'm not setting the #ContextID parameter.
Any idea why? I thought if I set it to the default value of NULL, then it would effectually be totally optional.
Update: here's how the SqlCommand gets set up, as best I can represent it here:
SqlCommand cmd = new SqlCommand("SP_GetStudents");
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter();
param.ParameterName = "#SortOrder";
param.Value = sortOrder;
param.Direction = ParameterDirection.Input;
SqlParameter param2 = new SqlParameter();
param2.ParameterName = "#SortColumn";
param2.Value = sortColumn;
param2.Direction = ParameterDirection.Input;
cmd.Parameters.Add(param);
cmd.Parameters.Add(param2);
cmd.Parameters.Add(new SqlParameter("#SortLetter", sortLetter));
cmd.Parameters.Add(new SqlParameter("#Status", status));
cmd.Parameters.Add(new SqlParameter("#PageIndex", pageIndex));
cmd.Parameters.Add(new SqlParameter("#PageSize", pageSize));
// here, the code splits a search expression into multiple parameters, looping over a switch statement like this:
foreach (string token in tokens)
{
switch(token)
{
case "Reference_No":
cmd.Parameters.Add(new SqlParameter("#Reference_No", (object)value ?? DBNull.Value));
break;
case "First_Name":
cmd.Parameters.Add(new SqlParameter("#First_Name", (object)value ?? DBNull.Value));
break;
case "Last_Name":
cmd.Parameters.Add(new SqlParameter("#Last_Name", (object)value ?? DBNull.Value));
break;
case "Middle_Name":
cmd.Parameters.Add(new SqlParameter("#Middle_Name", (object)value ?? DBNull.Value));
break;
case "Generation":
cmd.Parameters.Add(new SqlParameter("#Generation", (object)value ?? DBNull.Value));
break;
case "ContextID":
cmd.Parameters.Add(new SqlParameter("#ContextID", (object)value ?? DBNull.Value));
break;
}
}
cmd.Parameters.AddWithValue("#User_ID", userID);
// fires off cmd through a DAL
Here's the exception (of type System.Data.SqlClient.SqlException):
The parameterized query '(#Reference_No varchar(50),
#First_Name varchar(5' expects the parameter '#ContextID', which was not supplied.
I find this message kind of odd because the formatting seems jacked. Anyway, under the hood the command gets executed via a SqlDataAdapter which is used to fill a DataSet. The exception is thrown during the Fill method execution.
On this http://msdn.microsoft.com/en-us/library/ms187926.aspx link following line is mentioned..
The value of each declared parameter must be supplied by the user when the procedure is called unless a default value for the parameter is defined or the value is set to equal another parameter. If a procedure contains table-valued parameters, and the parameter is missing in the call, an empty table is passed in.
So based on that I can say that if you put the "Default" Key work your problem will be resolved.
Also on the same page information regarding default is mention with details like following.
default
A default value for a parameter. If a default value is defined for a parameter, the procedure can be executed without specifying a value for that parameter. The default value must be a constant or it can be NULL. The constant value can be in the form of a wildcard, making it possible to use the LIKE keyword when passing the parameter into the procedure. See Example C below.
Default values are recorded in the sys.parameters.default column only
for CLR procedures. That column will be NULL for Transact-SQL
procedure parameters.
Thanks,
Jigar

How do I return the IDENTITY for an inserted record from a stored Proecedure?

I am adding data to my database, but would like to retrieve the UnitID that is Auto generated.
using (SqlConnection connect = new SqlConnection(connections))
{
SqlCommand command = new SqlCommand("ContactInfo_Add", connect);
command.Parameters.Add(new SqlParameter("name", name));
command.Parameters.Add(new SqlParameter("address", address));
command.Parameters.Add(new SqlParameter("Product", name));
command.Parameters.Add(new SqlParameter("Quantity", address));
command.Parameters.Add(new SqlParameter("DueDate", city));
connect.Open();
command.ExecuteNonQuery();
}
...
ALTER PROCEDURE [dbo].[Contact_Add]
#name varchar(40),
#address varchar(60),
#Product varchar(40),
#Quantity varchar(5),
#DueDate datetime
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO DBO.PERSON
(Name, Address) VALUES (#name, #address)
INSERT INTO DBO.PRODUCT_DATA
(PersonID, Product, Quantity, DueDate) VALUES (#Product, #Quantity, #DueDate)
END
Add an output parameter to your procedure:
#new_id int output
and after the insert statement, assign it value:
set #new_id = scope_identity()
The add it to your calling code:
command.Parameters.Add("#new_id", SqlDbType.Int).Direction = ParameterDirection.Output;
and retrieve the value:
int newId = Convert.ToInt32(command.Parameters["#new_id"].Value);
With MSSQL its safer to use:
SET #AN_INT_OUTPUT_PARAM = SCOPE_IDENTITY()
Or simply
RETURN SCOPE_IDENTITY()
in the Stored procedure Add in the end
SELECT SCOPE_IDENTITY();
in the C#
define an integer outside using and assign it inside using
int UnitID;
UnitID = command.ExecuteScalar();
Search Books Online for OUTPUT clause if you have SQL server 2008. This is the best method.