SCOPE_IDENTITY() returns thousand number - c#

I have an insert query like the below. However, scopeIdentity does not return 42, it returns 1042.
This is the SQL Server table:
My code:
int masterId = 0;
using (SqlConnection cmd = new SqlConnection(connString))
{
using (SqlCommand conn = cmd.CreateCommand())
{
conn.CommandText = "INSERT INTO[MasterReportData]([ReportName],[CaseList],[EmployeeId],[datetime]) VALUES(#reportName, #caseList, #employeeId, #datetime) SET #ID = SCOPE_IDENTITY()";
conn.Parameters.Add("#reportName", SqlDbType.VarChar).Value = reportName;
conn.Parameters.Add("#caseList", SqlDbType.VarChar).Value = caseList;
conn.Parameters.Add("#employeeId", SqlDbType.Char).Value = employeeId;
conn.Parameters.Add("#datetime", SqlDbType.DateTime).Value = datetime;
conn.Parameters.Add("#ID", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Open();
conn.ExecuteNonQuery();
masterId = Convert.ToInt32(conn.Parameters["#ID"].Value);
cmd.Close();
}
}

Have a look at https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql
The description says:
Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, if two statements are in the same stored procedure, function, or batch, they are in the same scope.
In words: it Returns the last id and not the next to use. Therefore you can't use the INSERT command like that. What you can do is:
Configure your ID as auto-increment id. Then run the INSERT command and run SELECT SCOPE_IDENTITY() afterwards to find out which ID was used.

Related

how to get an auto incrementing stored procedure in mysql

I'm running the below code to call p_CreateRequest. All i want is to get the ID Back but i get an Field "ID" Does not have a default value error. HELP
using (var conn = Conn)
{
using (var cmd = new MySql.Data.MySqlClient.MySqlCommand("p_CreateRequest", conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new MySql.Data.MySqlClient.MySqlParameter("CREATED_DATE", cREATED_DATE));
cmd.Parameters.Add(new MySql.Data.MySqlClient.MySqlParameter("WORKFLOW_ID", wORKFLOW_ID));
cmd.Parameters.Add(new MySql.Data.MySqlClient.MySqlParameter("CREATED_BY_USER_ID", cREATED_BY_USER_ID));
cmd.Parameters.Add(new MySql.Data.MySqlClient.MySqlParameter("ID", iD));
cmd.Parameters["ID"].Direction = System.Data.ParameterDirection.Output;
cmd.ExecuteNonQuery();
iD = (int)cmd.Parameters["ID"].Value;
return iD;
}
}
the sprocs code is
CREATE DEFINER="finnsch"#"%" PROCEDURE "p_CreateRequest"(CREATED_DATE datetime,
WORKFLOW_ID int, CREATED_BY_USER_ID varchar(50),INOUT ID int)
BEGIN
DECLARE LASTCHANGEDATE Date;
SET LASTCHANGEDATE = Now();
INSERT INTO REQUEST
(CREATED_DATE,WORKFLOW_ID,CREATED_BY_USER_ID,
CURRENT_STEP_ID,LAST_ACTION_BY,LAST_EDIT_DATE)
select
CREATED_DATE,WORKFLOW_ID,CREATED_BY_USER_ID,s.ID,
CREATED_BY_USER_ID,LASTCHANGEDATE
from
STEP s where s.WORKFLOW_ID=WORKFLOW_ID and s.IS_INITIAL=1;
set ID = Last_Insert_ID();
END
Need to change the table and set ID to:
id int(20) NOT NULL AUTO_INCREMENT,
Also, check if MySql is in Strict SQL Mode. If it is, then need to run the query:
SET GLOBAL sql_mode=''.
You can also modify your my.cnf / my.ini to ensure you aren't setting STRICT_ALL_TABLES and/or STRICT_TRANS_TABLES. See this for more information:
Field 'id' doesn't have a default value?

Return ID if record exist, else Insert and return ID

I have the below C# code to check if the record does not exist, insert and return id. But also I need if the record exists, it return the value. What change should I make to C# and SQL part for this to happen? Database is sQL server. Do I still have to use ExecuteScalar() for this?
con.Open();
// Insert ClinRefFileTypeMaster
string command1 = string.Format(
"if NOT exists (select * from [ClinRefFileTypeMaster] where [ClinRefTypeName] = '{0}') Insert into [ClinRefFileTypeMaster] ([ClinRefTypeName]) output INSERTED.[ClinRefTypeID] VALUES('{0}')",
dataToParse[i][0]
);
SqlCommand ClinRefFileTypeMaster = new SqlCommand(command1, con);
// check if there is an value
object checkValue = ClinRefFileTypeMaster.ExecuteScalar();
if (checkValue != null)
ClinRefFileTypeId = (int)checkValue;
A stored procedure to do all the stuff for you would look something like.....
CREATE PROCEDURE usp_Get_ClinRefTypeID
#ClinRefTypeName VARCHAR(100),
#ClinRefTypeID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #NewID TABLE(ClinRefTypeID INT);
SELECT #ClinRefTypeID = [ClinRefTypeID]
FROM [ClinRefFileTypeMaster]
where [ClinRefTypeName] = #ClinRefTypeName;
IF (#ClinRefTypeID IS NULL)
BEGIN
INSERT INTO [ClinRefFileTypeMaster] ([ClinRefTypeName])
OUTPUT inserted.[ClinRefTypeID] INTO #NewID(ClinRefTypeID)
VALUES(#ClinRefTypeName)
SELECT #ClinRefTypeID = [ClinRefTypeID] FROM #NewID
END
END
And your C# code would look something like.....
con.Open();
// Insert ClinRefFileTypeMaster
SqlCommand cmd = new SqlCommand("usp_Get_ClinRefTypeID", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ClinRefTypeID", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#ClinRefTypeName", dataToParse));
// get the value back from the output parameter
cmd.ExecuteNonQuery();
int ClinRefTypeName = Convert.ToInt32(cmd.Parameters["#ClinRefTypeID"].Value);
There are many ways to achieve this. 1) You can do it all in inline Sql 2) you can do it all in stored proc. 3) You can do it all in code but split the code as this code is frankly doing too much. In general I would avoid insert/query in the same method.
Also try to use SqlParameters instead of building the query as string concat.
I would propose something like this which makes the code a bit more readable
public int InsertAndRetrieveClientRefId(string clientRefTypeName)
{
int id = GetIdIfRecordExists(clientRefTypeName);
if (id == 0)
{
// insert logic here
id = GetIdIfRecordExists(clientRefTypeName);
}
return id;
}
public int GetIdIfRecordExists(string clientRefTypeName)
{
int id = 0;
string command = "select id from ClinRefFileTypeMaster where ClinRefTypeName = #ClinRefTypeName";
SqlParameter nameParameter = new SqlParameter("#ClinRefTypeName", System.Data.SqlDbType.NVarChar, 10) { Value = clientRefTypeName };
using (SqlConnection connection = new SqlConnection("ConnectionString"))
{
using (SqlCommand cmd = new SqlCommand(command))
{
cmd.Parameters.Add(newParameter);
connection.Open();
cmd.Connection = connection;
int.TryParse(cmd.ExecuteScalar().ToString(), out id);
}
}
return id;
}
do all this in database i.e in store procedure
if not exists (select 1 from [ClinRefFileTypeMaster] where [ClinRefTypeName] =#name)
begin
Insert into [ClinRefFileTypeMaster] ([ClinRefTypeName]) values (#name)
end
else
begin
select (as desired) from ClinRefFileTypeMaster where where [ClinRefTypeName] =#name
end
this will either insert new record or it will select already inserted information
Youll need to add an IF EXISTS clause to the SQL statement as well, checking for the same conditions, and providing logic to return a value.
It seems using ExecuteReader would be better if you need it to return the value from the database.
2¢
I personally would split the logic into two queries and run the If statement within c# checking if the value is in the database, then updating the database else returning a value from the database
conn.open()
int CheckDb;
String Command1 = "select * from [ClinRefFileTypeMaster] where [ClinRefTypeName] = #ClinRefFileTypeId";
using (SqlCommand ClinRefFileTypeMaster = new SqlCommand(command1, con);
{
cmd.Parameters.AddWithValue("#ClinRefFileTypeId", {0});
CheckDb = (int)ClinRefFileTypeMaster.ExecuteScalar();
}
If (CheckDb != 0)
//Logic for returning the value from the database
Else
//Here you can request user check data or insert the value into the database.
if you want to perform Instert operation, I think its better you call a stored procedure and write your query in the procedure. It will be safer.
SqlCommand command = new SqlCommand("procedureName",con);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue(“#value1”, txtValue1.Text);
command.Parameters.AddWithValue(“#value2”, Value2);
int value = command.ExecuteScalar();
IF EXISTS (SELECT 1 FROM Table WHERE FieldValue='')
BEGIN
SELECT TableID FROM Table WHERE FieldValue=''
END
ELSE
BEGIN
INSERT INTO TABLE(FieldValue) VALUES('')
SELECT SCOPE_IDENTITY() AS TableID
END
If you want to pass the querystring, you can call select query and if it returns null perform a insert opeartion and use scope_Identity() to get the ID
INSERT INTO YourTable(val1, val2, val3 ...)
VALUES(#val1, #val2, #val3...);
SELECT SCOPE_IDENTITY();

Error on SQL Server Insert stored procedure

I'm trying to simply insert data into a table in SQL Server from a C# winforms application.
Currently when the executing the query I'm receiving the error:
Incorrect syntax near 'soAddItems'
Here is my insert code of the class handling my database CRUD operations:
Note: As test data:
itemName = "test"
skuNo = "a123"
itemPrice = 2.99
stockItemToAdd = 3
itemPic = "C:\Users\Name\Pictures\pic.png"**
Code:
public virtual void AddItem(string itemName, string skuNo, double itemPrice, int stockAmountToAdd, string itemPic)
{
using (SqlConnection open = new SqlConnection(connectionString))
{
SqlCommand insertCommand = new SqlCommand("soAddItems", open);
open.Open();
insertCommand.Parameters.Add("#itemName", SqlDbType.NChar).Value = itemName;
insertCommand.Parameters.Add("#skuNo", SqlDbType.VarChar).Value = skuNo;
insertCommand.Parameters.Add("#itemPrice", SqlDbType.Decimal).Value = itemPrice;
insertCommand.Parameters.Add("#instockAmount", SqlDbType.BigInt).Value = stockAmountToAdd;
insertCommand.Parameters.Add("#lastSold", SqlDbType.DateTime).Value = DateTime.Today;
insertCommand.Parameters.Add("#itemPic", SqlDbType.NChar).Value = itemPic;
//***** Error on the execute*****
insertCommand.ExecuteNonQuery();
};
}
SQL Server stored procedure:
ALTER PROC [dbo].[soAddItems]
#itemName nchar,
#skuNo varchar,
#itemPrice float,
#instockAmount bigint,
#lastSold dateTime,
#itemPic varchar
AS
BEGIN
INSERT INTO items (itemName, skuNo, itemPrice, instockAmount, lastSold, itemPic)
VALUES (#itemName, #skuNo, #itemPrice, #instockAmount, #itemPic)
END
Can anyone tell me where I'm going wrong?
You need to tell the SqlCommand command type as stored procedure.
Try this:
insertCommand.CommandType = CommandType.StoredProcedure;
It looks like you forget to assign your SqlCommand.CommandType property.
Because it is Text as a default.
insertCommand.CommandType = CommandType.StoredProcedure;
Besides the missing CommandType.StoredProcedure, you have a second major flaw: if you define a parameter like this: #skuNo varchar - then you get a string of 1 character length!
That's usually not what you want - you should ALWAYS specify a length when defining parameters and variables in T-SQL!
Use: #skuNo varchar(50) or whatever length you need

Get auto_increment id from table

I have this code:
string conStr = ConfigurationManager.ConnectionStrings["BackgammonGame"].ConnectionString;
SqlConnection con = new SqlConnection(conStr);
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = ("INSERT INTO Game (playerA, playerB) OUTPUT INSERTED.gameID VALUES (#playerA, #playerB)");
cmd.Parameters.Add("#playerA", SqlDbType.NVarChar).Value = firstPlayer;
cmd.Parameters.Add("#playerB", SqlDbType.NVarChar).Value = secondPlayer;
cmd.ExecuteNonQuery();
int id = (int)cmd.ExecuteScalar();
con.Close();
When I insert into this table, I have an auto_increment int primary key column called gameID, and I declared in the sql statement that I want the gameID in output.
my problem is that when I write this line in the code: int id = (int)cmd.ExecuteScalar(); the inserted parameters apear twice in the table (2 rows with the same info.), but when I delete it it's ok.
I need this row so I can use this id in other table.
Change your command text with this and try
cmd.CommandText = ("INSERT INTO Game (playerA, playerB) VALUES (#playerA,#playerB);
SELECT SCOPE_IDENTITY()");
SCOPE IDENTITY returns the identity value of last inserted row. Hence that will returns the identity filed of the inserted row using the insert query
EDIT
You are executing the query two times
cmd.ExecuteNonQuery(); // Avoid this
int id = (int)cmd.ExecuteScalar();// This is enough
In both case your query gets executed and it cause insertion twice.
ExecuteNonQuery() will execute the insert query and will returns the number of rows affected.
Where as ExecuteScalar() will return the result of the select scope_identity() staement which is the identity column of the inserted row.
Here is your code
con.Open();
cmd.CommandText = ("INSERT INTO Game (playerA, playerB) VALUES (#playerA,#playerB);
SELECT SCOPE_IDENTITY()");
cmd.Parameters.Add("#playerA", SqlDbType.NVarChar).Value = firstPlayer;
cmd.Parameters.Add("#playerB", SqlDbType.NVarChar).Value = secondPlayer;
int id = Convert.ToInt32(cmd.ExecuteScalar());
con.Close();
Modify your command like this
INSERT INTO YourTable(val1, val2, val3 ...)
VALUES(#val1, #val2, #val3...)
SELECT SCOPE_IDENTITY()
But i personally prefer to write a stored procedure and return the primary key as an output parameter of that sp.

Run stored procedure in C#, pass parameters and capture the output result

This is a simple task that I want to acheive but ASP.NET makes it quite difficult, next to impossible. I followed this question
Running a Stored Procedure in C# Button but found out ExecuteNonQuery does not return the output from query.
I tried this other approach but can't seem to pass the paremeters in this way
SqlConnection myConnection = new SqlConnection(myconnectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandText = "usp_GetCustomer";
myCommand.SelectParameter <-- does not exist
Can someone write this simple code, how can I implement it? Basically I am passing a #username and #month (both character strings) to stored procedure and it returns a number that I want to capture and assign to a label control.
Thank you
The output from my query is this. It runs a complex query, create a temp table and then it runs
select ##rowcount
and I am capturing that.
Don't use SqlCommand.ExecuteNonQuery() if you actually want data from a result set.
Make sure your procedure uses set nocount on
Then use SqlCommand.ExecuteScalar()
return (int)myCommand.ExecuteScalar(); // value of select ##rowcount
Edit: As for your parameters:
myCommand.Parameters.AddWithValue("#username","jsmith");
myCommand.Parameters.AddWithValue("#month","January");
I prefer using linq-to-sql to handle stored procedures. Create a linq-to-sql model, where you add the SP you want to call. This will expose the SP as a function on the generated data context, where the parameters are ordinary C# functions. The returned values will be exposed as a collection of C# objects.
If you have multiple results from the SP things get a bit more complicated, but still quite straight forward.
Use the Parameters collection of the command to set the parameters, and the ExecuteScalar to run the query and get the value from the single-row single-column result.
Use using blocks to make sure that the connection and command are closed and disposed properly in any situation. Note that you have to provide the connection to the command object:
int result;
using (SqlConnection connection = new SqlConnection(myconnectionString)) {
using (SqlCommand command = new SqlCommand(connection)) {
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "usp_GetCustomer";
command.Parameters.Add("#username", SqlDbType.VarChar).Value = username;
command.Parameters.Add("#month", SqlDbType.VarChar).Value = month;
connection.Open();
result = (int)myCommand.ExecuteScalar();
}
}
using(SqlConnection myConnection = new SqlConnection(myconnectionString))
{
SqlCommand myCommand = new SqlCommand();
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandText = "usp_GetCustomer";
myCommand.Parameters.Add("#USER_NAME", SqlDbType.VarChar).Value = sUserName; // user name that you pass to stored procedure
myCommand.Parameters.Add("#Month", SqlDbType.VarChar).Value = iMonth; // Month that you pass to stored procedure
// to get return value from stored procedure
myCommand.Parameters.Add("#ReturnValue", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
myConnection .Open();
myCommand.ExecuteScalar();
// Returnvalue from stored procedure
return Convert.ToInt32(command.Parameters["#ReturnValue"].Value);
}
Simple code to get return value from SQL Server
SqlConnection myConnection = new SqlConnection(myconnectionString);
SqlCommand myCommand = new SqlCommand();
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandText = "usp_GetCustomer";
myCommand.Parameters.Add("#USER_NAME", SqlDbType.VarChar).Value = sUserName; // user name that you pass to the stored procedure
myCommand.Parameters.Add("#Month", SqlDbType.VarChar).Value = iMonth; //Month that you pass to the stored procedure
// to get return value from the stored procedure
myCommand.Parameters.Add("#ReturnValue", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
myConnection .Open();
myCommand.ExecuteScalar();
// Returnvalue from the stored procedure
int iReturnValue = Convert.ToInt32(command.Parameters["#ReturnValue"].Value);

Categories

Resources