Read Id of last inserted - c#

I have been through everything for a couple weeks now only to find statements working at the database level. Below is my code and I feel that I am very near the answer but keep getting -1 returned from SCOPE_IDENTITY(). Customer_Name is saving to the table just fine along with the auto increment. I just need the Customer_ID so that I can place it in the Customer_Address table for the one to many identification of the address to the customer.
Thanks in advance for your help.
if (customer_ID == "")
{
// add new customer
string SQL = "INSERT INTO Customer (Customer_Name) VALUES (#customer_Name)";
SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection);
sqlCommand.Parameters.Add("#customer_Name", SqlDbType.VarChar, 100).Value = customer_Name;
// get last inserted Customer_ID
string SQL_customerId = "SELECT SCOPE_IDENTITY()";
SqlCommand sqlCommand_customerId = new SqlCommand(SQL_customerId, sqlConnection);
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
sqlCommand_customerId.ExecuteNonQuery();
// string SQL_ = "SELECT Customer_ID FROM Customer";
// SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection);
// int maxId = Convert.ToInt32(sqlCommand.ExecuteScalar());
sqlConnection.Close();
}

You need to have the SCOPE_IDENTITY within the same transaction as your insert. The following should help you.
string SQL = "INSERT INTO Customer (Customer_Name) VALUES (#customer_Name); SELECT Customer_Id FROM Customer WHERE Customer_Id = SCOPE_IDENTITY();";
SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection);
sqlCommand.Parameters.Add("#customer_Name", SqlDbType.VarChar, 100).Value = customer_Name;
sqlConnection.Open();
int id = (int) sqlCommand.ExecuteScalar();

try something like this..
Output clause will help you to get the inserted value and with that we can insert into another temp or physical table. This is just an idea to your question
CREATE TABLE customer
(
id INT IDENTITY(1, 1),
addres VARCHAR(500)
)
CREATE TABLE customeraddrs
(
custid INT
)
INSERT INTO customer
output inserted.id
INTO customeraddrs
VALUES ('a'),
('b')
SELECT *
FROM customer
SELECT *
FROM customeraddrs

Related

Trying to insert int variable into SQL Server table

protected void addItem_Click(object sender, EventArgs e)
{
String CS = ConfigurationManager.ConnectionStrings["DatabaseConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
string PID;
Button oButton = (Button)sender;
PID = oButton.CommandArgument.ToString();
int productId = Convert.ToInt32(PID);
Debug.Write(productId);
string email = (string)(Session["email"]);
SqlCommand cmd = new SqlCommand("insert into basket (productId, email) values( productId,'" + email + "')", con);
con.Open();
cmd.ExecuteNonQuery();
}
}
When my query executes, I get an error
Invalid column name 'productId'
As you can see, I have converted a string into an integer variable, I have printed off the variable to check what it is returning. It does return a int as expected, but for some odd reason i can not insert into to my table. Any help would be great.
Hope productId is not the primary key of the basket table.
Then,instead of
SqlCommand cmd = new SqlCommand("insert into basket (productId, email) values( productId,'" + email + "')", con);
Modify like below
SqlCommand cmd = new SqlCommand("insert into basket (productId, email) values( #productId,#email)", con);
cmd.Parameters.Add(new SqlParameter("#productId",productId );
cmd.Parameters.Add(new SqlParameter("#email",email );
Why suggested to modify is to avoid SQLInjection attack. If you are unaware about that please go through the below link and learn it
https://en.wikipedia.org/wiki/SQL_injection
Two issues here, number 1, and a big one, parameterize that query! You're opening yourself up to SQL injection attacks with code like that.
The second is that you're not actually passing in your productId variable, you're telling it to use the value for the productId column - which is also the column you're trying to insert into.
SqlCommand cmd = new SqlCommand("insert into basket (productId, email) values (#productId, #email)");
cmd.Parameters.AddWithValue("#productId", productId);
cmd.Parameters.AddWithValue("#email", email);
I can't stress enough how dangerous it is to dump user input into SQL that's going to be run directly on your database.

How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery

I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}

Assign Primary Key of Table 1 as a Foreign Key in Table 2 using SQL and C#

I have tables Member and Office which use an auto-increment primary key, Member_Id and Office_Id. I am inserting data into the tables but would like to have primary key of the Member table inserted on the Office Table as a foreign key, so that a member is assigned to an office record. Please assist. Below is a snippet of my code for inserting the records but I just do not know how to link the two tables.
protected void capture()
{
string CS = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
using (SqlConnection conn = new SqlConnection(CS))
{
conn.Open();
SqlCommand com = new SqlCommand();
SqlParameter myParam = new SqlParameter();
com.CommandText = "INSERT into Member(Appointment_Number, Initials, Surname, Designation) VALUES (#Appointment_Number, #Initials, #Surname, #Designation)";
com.Parameters.AddWithValue("#Appointment_Number", txtAppointmentNumber.Text);
com.Parameters.AddWithValue("#Initials", txtInitials.Text);
com.Parameters.AddWithValue("#Surname", txtSurname.Text);
com.Parameters.AddWithValue("#Designation", ddlDesignation.Text);
com.Connection = conn;
com.ExecuteNonQuery();
com.Parameters.Clear();
//Insert records into the office table
com.CommandText = "INSERT into Offices(Office_Number, Status, Building, Branch, Floor) VALUES (#Office_Number, #Status, #Building, #Branch, #Floor)";
com.Parameters.AddWithValue("#Office_Number", txtOffNo.Text);
com.Parameters.AddWithValue("#Status", ddlOStatus.Text);
com.Parameters.AddWithValue("#Building", ddlBuilding.Text);
com.Parameters.AddWithValue("#Branch", ddlBranch.Text);
com.Parameters.AddWithValue("#Floor", ddlFloors.Text);
com.Connection = conn;
com.ExecuteNonQuery();
com.Parameters.Clear();
if (IsPostBack)
{
Response.Redirect("~/Pages/MemberDetails.aspx");
}
}
}
I think, you want to set a relation between offices and members 1 to n.
So to do that, lets add officeid field in members table, insert the office record before the member and change the code like this;
protected void capture()
{
string CS = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
using (SqlConnection conn = new SqlConnection(CS))
{
conn.Open();
SqlCommand com = new SqlCommand();
SqlParameter myParam = new SqlParameter();
//Insert records into the office table
com.CommandText = "INSERT into Offices(Office_Number, Status, Building, Branch, Floor) VALUES (#Office_Number, #Status, #Building, #Branch, #Floor)";
com.Parameters.AddWithValue("#Office_Number", txtOffNo.Text);
com.Parameters.AddWithValue("#Status", ddlOStatus.Text);
com.Parameters.AddWithValue("#Building", ddlBuilding.Text);
com.Parameters.AddWithValue("#Branch", ddlBranch.Text);
com.Parameters.AddWithValue("#Floor", ddlFloors.Text);
com.Connection = conn;
com.ExecuteNonQuery();
com.Parameters.Clear();
com.CommandText = "select max(Office_Id) from Offices";
int officeid = Convert.ToInt32(com.ExecuteScalar());
com.CommandText = "INSERT into Member(officeid,Appointment_Number, Initials, Surname, Designation) VALUES (#officeid,#Appointment_Number, #Initials, #Surname, #Designation)";
com.Parameters.AddWithValue("#officeid", officeid);
com.Parameters.AddWithValue("#Appointment_Number", txtAppointmentNumber.Text);
com.Parameters.AddWithValue("#Initials", txtInitials.Text);
com.Parameters.AddWithValue("#Surname", txtSurname.Text);
com.Parameters.AddWithValue("#Designation", ddlDesignation.Text);
com.Connection = conn;
com.ExecuteNonQuery();
com.Parameters.Clear();
if (IsPostBack)
{
Response.Redirect("~/Pages/MemberDetails.aspx");
}
}
}
Once you've inserted into your first table, using the same connection, SELECT SCOPE_IDENTITY() to get the auto-assigned identity value just created. You can then use that to insert into the second table.
Using SCOPE_IDENTITY() will ensure that you always get the id that you just created. If your system is being used by multiple users concurrently, you don't want to risk picking up the identity value created by another user that happened to be inserting data at the same time as you.
e.g. after your first insert:
com.CommandText = "SELECT SCOPE_IDENTITY()";
int my_id_just_created = Convert.ToInt32(com.ExecuteScalar());
The simplest way to do this is probably to insert your Office table first, get the scope identity, and put that in the FK of you member insert. To get the scope identity just use this syntax :
INSERT INTO YourTable
(val1, val2, val3 ...)
VALUES(#val1, #val2, #val3...);
SELECT SCOPE_IDENTITY();
Then you use com.ExecuteScalar() that will return you an Int with the PK of the Office table that you can use as the FK of the Member table.

How to use insert and update command using c#

I have GridView and I am trying to check Task_ID from a table, if it is found then I want to update the record but if Task_ID is not found in the table then I want to insert it into my table. My code now does the insert part but it does not do the update part of the code. I was wondering how you can do this within the same code. Please help. thanks
here is my code:
int index = 0;
foreach (GridViewRow row in myGV.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
Label ID = row.FindControl("lbl_ID") as Label;
string UID = Request.Form[row.FindControl("hfUId").UniqueID];
DateTime strDate = DateTime.Now;
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["myCon"].ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "insert into myTable(TID, USR_ID, UPDT_DT) values(#ID, #USR_ID, #UPDT_DT) ";
cmd.Parameters.Add("#ID", SqlDbType.VarChar).Value = ID.Text;
cmd.Parameters.Add("#USR_ID", SqlDbType.VarChar).Value = UID.ToString();
cmd.Parameters.Add("#UPDT_DT", SqlDbType.VarChar).Value = strDate.Date;
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
con.Dispose();
cmd.Dispose();
}
index++;
}
There is a MERGE command in SQL for this purpose. Here is an example that might work for you:
Merge myTable As T
Using (Select Task_ID From myTable) As Src (Src_ID)
ON (T.Task_ID = Src.Src_ID)
WHEN MATCHED THEN
UPDATE SET T.UPDT_DT = 'your new value'
WHEN NOT MATCHED THEN
INSERT (TASK_ID, USR_ID, UPDT_DT)
VALUES (#TASK_ID, #USR_ID, #UPDT_DT);
change 'your new value' to the correct update statement
Replace the command text as below:
if not exists (select task_id from mytable where task_id = #task_id)
insert into myTable(TASK_ID, USR_ID, UPDT_DT) values(#TASK_ID, #USR_ID, #UPDT_DT)
else
update mytable set USR_ID = #USR_ID, UPDT_DT = #UPDT_DT where task_id = #TASK_ID
I would first query the database to see if the task_id existed... declare cmd, define it with a sql command like "Select count(*) from myTable where Task_ID = '" & Task_ID.text & "'" and assign that to some variable x. Then follow that with "if x <> 0 then --> define your cmd as an insert statement here, ELSE --> define cmd as "Update myTable set blah blah = values WHERE task_ID = " & task_ID.text.

Insert data into SQL Server from C# code

I have a table student (id, name). Then I have one textbox, for entering the name, when click on submit button, it inserts the data into the database. So how can I insert only to name, not id because id is auto increment?
I tried this
insert into student(id, name) values(,name)
but it is not insert to my table.
This is my code :
protected void Button1_Click(object sender, EventArgs e)
{
string test = txtName.Text;
SqlConnection conn = new SqlConnection(#"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Person.mdf;Integrated Security=True;User Instance=True");
string sql = "insert into student(name) values ('test')";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
}
finally
{
conn.Close();
}
}
INSERT INTO student (name) values ('name')
Omit the id column altogether, it will be populated automatically. To use your variable, you should parameterise your SQL query.
string sql = "INSERT INTO student (name) values (#name)";
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = test;
cmd.ExecuteNonQuery();
You should never attempt to do this by constructing a SQL string containing the input value, as this can expose your code to SQL injection vulnerabilities.
You better use parameters when you insert data.
try
{
string sql = "insert into student(name) values (#name)";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#name", test); // assign value to parameter
cmd.ExecuteNonQuery();
}
}
}
catch (SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
}
You don't need to mention the ID in first part.
insert into student(name) values('name')
I was facing this problem and after trying various solution found at stack overflow, i could summarize the experience as follows:
commands executed in command shell of mssql like:
insert into table_name (val1,val2,val3,val4) VALUES ("val1","val2",0,"val4")
go
or
insert into table_name VALUES ("val1","val2",0,"val4")
go
work when typed directly in the mssql database prompt,
But when it is required to use the the insert statement from c#, it is required to be kept in mind that string needs to be surrounded by an additional pair of single quites, around the strings, like in:
SqlConnection cnn;
string connetionString = "Data Source=server_name;Initial Catalog=database_name;User ID=User_ID;Password=Pass_word";
cnn = new SqlConnection(connetionString);
SqlCommand myCommand = new SqlCommand("insert into table_name (val1,val2,val3,val4) VALUES ('val1','val2',0,'val4');", cnn);
//or
//SqlCommand myCommand = new SqlCommand(insert into table_name VALUES ('val1','val2',0,'val4');", cnn);
cnn.Open();
myCommand.ExecuteNonQuery();
cnn.Close();
the problem here is that most people, like myself, try to use <\"> in the place of double quotes <">that is implemented as in the above command line case, and SQL executor fails to understand the meaning of this.
Even in cases where a string needs to be replace, ensure that strings are surrounded by single quotation, where a string concatination looks like a feasible solution, like in:
SqlCommand myCommand = new SqlCommand("insert into table_name (val1,val2,val3,val4) VALUES ('"+val1+"','val2',0,'val4');", cnn);
string sql = "INSERT INTO student (name) values (#name)";
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = test;
cmd.ExecuteNonQuery();
Try the following query,
insert into student(name) values(name)
SQL Server internally auto increments the id column when u insert the data since u said it is auto increment. If it is not working, the u have to check the identity column in the db.
use the key word "identity" to auto increment the id column
Refer : http://technet.microsoft.com/en-us/library/aa933196(v=sql.80).aspx
create table table_name( id int PRIMARY KEY IDENTITY )
and you no need to mention the "id" in the insert query

Categories