Executing an insert statement and put id in a local variable? - c#

SqlDataSource myQuiz = new SqlDataSource();
myQuiz.ConnectionString = ConfigurationManager.ConnectionStrings["yafnet"].ToString();
myQuiz.InsertCommand = "INSERT INTO [QuizTable]([Quiz_Title],[Quiz_Description]) VALUES (#Quiz_Title,#Quiz_Description)";
myQuiz.InsertParameters.Add("Quiz_Title",Quiz_Title.Text);
myQuiz.InsertParameters.Add("Quiz_Description",Quiz_Description.Text);
myQuiz.Insert();
Response.Redirect("QuizQuests.aspx");
Is there a way to get back the automatically generated ID of the new row and put it in a local variable?
Thanks a lot in advance,
Adrian

Use
SELECT IDENT_CURRENT(‘QuizTable’)
It returns the last IDENTITY value produced in a table, regardless of the connection that created the value, and regardless of the scope of the statement that produced the value.
IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope.

If you want to be 100% sure that you really get the identity from your insert in your actual QuizTable, you should use SCOPE_IDENTITY() (as already mentioned by Luiggi Mendoza in his comment), and not ##IDENTITY or IDENT_CURRENT.
##IDENTITY might not work because it will return the identity from the last insert that happened from your connection. So if there is a trigger on your QuizTable which inserts a row in another table that has an identity column as well, ##IDENTITY will return the value from that second insert, and not that of the original insert into the QuizTable .
IDENT_CURRENT will return the last identity value for your table (and only for your table, so it doesn't matter if there are triggers like the one in the previous example).
But it returns the last identity value for any session. So if another row is inserted from another session between your INSERT and your IDENT_CURRENT, you'll get the identity value from that row, not from yours.

#Adrian De Barro: hi you can use following code to get inserted record id and save in variable
in your sqlquery add following statement:
return ##IDENTITY
and your C# code will be as follows:
SqlConnection cn = new
SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
cn.Open();
SqlCommand cmd = new SqlCommand(procname, cn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter str = new SqlParameter("name", SqlDbType.VarChar);
str.Direction = ParameterDirection.ReturnValue;
foreach (SqlParameter par in param)
{
cmd.Parameters.Add(par);
}
string name = Convert.ToString(cmd.ExecuteScalar());
cmd.Dispose();
cn.Close();
return name;

Related

I'm having some issues with my scope identity retrieving a ID from an identity column

I'm having some issues with my scope identity retrieving a ID from an identity column.
This is my code:
cmd = connection.CreateCommand();
cmd.CommandText = "Insert Into oc_manufacturer (name, sort_order) Values(#name, #sort_order);SELECT CAST(scope_identity() AS int)";
cmd.Parameters.AddWithValue("#name", sManufacturer);
cmd.Parameters.AddWithValue("#sort_order", 0);
iManufacturerID = (int)cmd.ExecuteScalar();
cmd.ExecuteNonQuery();
This is inside a try catch. and it hits my catch when i step through it at the 2nd last line of code. I am still very new to using this scope identity. Usually i would create a whole new select statement with the same variables as my insert statement. But that is very long so truing to get this right. any help?
Perhaps I am wrong, but you have marked your question as MySql. In that database system, you retrieve the last inserted autoincrement value with LAST_INSERT_ID() function
cmd.CommandText = #"Insert Into oc_manufacturer (name, sort_order)
Values(#name, #sort_order);
SELECT LAST_INSERT_ID()";
Also there is no need to call ExecuteNonQuery, the call to ExecuteScalar will work on both statements but will return the value of the last SELECT

SQL Server database last_rowID

I have a C# app with have to use SQL Server database with 1 table (All_Data) and 5 columns (ID, Name, Surename, Age,Location)
Before inserting a new row how can I find out or get the value of the last ID in the table
I have a following code but it,a not work well
string query = "SELECT MAX(ID) FROM All_Data";
SqlCommand comSelect;
comSelect = new SqlCommand(query, connection);
int ID = (int)comSelect.ExecuteScalar();
ERROR message:
ExecuteScalar: Connection property has not been initialized
Please help me
First, from your code it is not clear what is the value of the variable connection.
From the error message it seems that you don't have initialized this variable and thus you get the error. (connection = new SqlConnection(....);)
However, this is not the correct way to handle this scenario.
You need to make the ID column an IDENTITY column and then don't try to retrieve its value before executing any INSERT.
An IDENTITY column receives its value directly from the database when there is a new record to insert. And letting the database code work on this data it is the best option if you want to be safe from concurrency issues.
If you need to retrieve the ID value after an INSERT query because you need it as a Foreign Key in other tables or for your own code, then you could simply use the T-SQL command
SELECT SCOPE_IDENTITY()
For example, suppose you have to insert a record in that table, and you want to know the IDENTITY value assigned to the ID column
string query = #"INSERT INTO All_Data(Name,Surename,Age,Location)
VALUES(#name, #surname, #age, #loc);
SELECT SCOPE_IDENTITY()";
using(SqlConnection connection = new SqlConnection(connectionString))
using(SqlCommand cmd = new SqlCommand(query, connection))
{
connection.Open();
cmd.Parameters.AddWithValue("#name", yourNameValue);
.... other parameters ...
int newID = Convert.ToInt32(cmd.ExecuteScalar());
}
As you can see, this code doesn't try to pass a value for the ID column. It pass just the other fields with a parameterized query. But at the end of the first query there is a call to SELECT SCOPE_IDENTITY() and this returns whatever value the database has assigned to the column ID (of course you should have set the IDENTITY property on the field).
This will work correctly in multiuser and concurrent scenario
The error fires when the command doesn't have a connection. Please check connection is open.
Error saysExecuteScalar: Connectio property has not been initialized
double Check your connection string whether it is defined properly. You can check here to know how to define connection string.
you have not opened connection so open it before use :
comSelect = new SqlCommand(query, connection);
connection.Open();
int ID = (int)comSelect.ExecuteScalar();
connection.Close();

Return IDENT_CURRENT which was inserted

I have INSERT INTO SqlCommand and I need to display after INSERT INTO the IDENT_CURRENT which was inserted with these values
SqlCommand sc = new SqlCommand("INSERT INTO kliplat (datum,text,castka,akce,subkey,priznak,rocnik) values (#datum,#text,#castka,#akce,#subkey,#priznak,#rocnik)", spojeni);
spojeni.Open();
sc.Parameters.AddWithValue("#subkey", vyber_id_kli);
sc.Parameters.AddWithValue("#akce", vyberakce);
sc.Parameters.AddWithValue("#priznak", vyberplat);
sc.Parameters.AddWithValue("#datum", maskedTextBox1.Text);
sc.Parameters.AddWithValue("#text", textBox1.Text);
sc.Parameters.AddWithValue("#castka", textBox2.Text);
sc.Parameters.AddWithValue("#rocnik", rocnik);
sc.ExecuteReader();
spojeni.Close();
This IDENT_CURRENT is: INTEGER IDENTITY PRIMARY KEY
Now I was dealing with this issue like this:
SqlCommand comm = new SqlCommand("SELECT IDENT_CURRENT ('mytable')", conn);
spojeni.Open();
int max = Convert.ToInt32(comm.ExecuteScalar());
spojeni.Close();
But I found out that this is extremely hazardous to do.
Thank you all for your time reading this.
You could use a command that returns the newly inserted id:
SqlCommand sc = new SqlCommand(#"
INSERT INTO kliplat (datum,text,castka,akce,subkey,priznak,rocnik)
VALUES (#datum,#text,#castka,#akce,#subkey,#priznak,#rocnik);
SELECT scope_identity();
", spojeni);
...
var newIdentity = (long) sc.ExecuteScalar();
I think you may consider using scope_identity() function instead of ident_current.
SCOPE_IDENTITY, IDENT_CURRENT, and ##IDENTITY are similar functions
because they return values that are inserted into identity columns.
IDENT_CURRENT is not limited by scope and session; it is limited to a
specified table. IDENT_CURRENT returns the value generated for a
specific table in any session and any scope. For more information, see
IDENT_CURRENT (Transact-SQL). SCOPE_IDENTITY and ##IDENTITY return the
last identity values that are generated in any table in the current
session. However, SCOPE_IDENTITY returns values inserted only within
the current scope; ##IDENTITY is not limited to a specific scope.
Assuming your field is called ID; add this to your query:
OUTPUT INSERTED.ID
And catch the result in your c# code

How can i get the ##IDENTITY returned from a INSERT from MySQL (2008) using C# [duplicate]

Using C# in Visual Studio, I'm inserting a row into a table like this:
INSERT INTO foo (column_name)
VALUES ('bar')
I want to do something like this, but I don't know the correct syntax:
INSERT INTO foo (column_name)
VALUES ('bar')
RETURNING foo_id
This would return the foo_id column from the newly inserted row.
Furthermore, even if I find the correct syntax for this, I have another problem: I have SqlDataReader and SqlDataAdapter at my disposal. As far as I know, the former is for reading data, the second is for manipulating data. When inserting a row with a return statement, I am both manipulating and reading data, so I'm not sure what to use. Maybe there's something entirely different I should use for this?
SCOPE_IDENTITY 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, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can use SqlCommand.ExecuteScalar to execute the insert command and retrieve the new ID in one query.
using (var con = new SqlConnection(ConnectionString)) {
int newID;
var cmd = "INSERT INTO foo (column_name)VALUES (#Value);SELECT CAST(scope_identity() AS int)";
using (var insertCommand = new SqlCommand(cmd, con)) {
insertCommand.Parameters.AddWithValue("#Value", "bar");
con.Open();
newID = (int)insertCommand.ExecuteScalar();
}
}
try this:
INSERT INTO foo (column_name)
OUTPUT INSERTED.column_name,column_name,...
VALUES ('bar')
OUTPUT can return a result set (among other things), see: OUTPUT Clause (Transact-SQL). Also, if you insert multiple values (INSERT SELECT) this method will return one row per inserted row, where other methods will only return info on the last row.
working example:
declare #YourTable table (YourID int identity(1,1), YourCol1 varchar(5))
INSERT INTO #YourTable (YourCol1)
OUTPUT INSERTED.YourID
VALUES ('Bar')
OUTPUT:
YourID
-----------
1
(1 row(s) affected)
I think you can use ##IDENTITY for this, but I think there's some special rules/restrictions around it?
using (var con = new SqlConnection("connection string"))
{
con.Open();
string query = "INSERT INTO table (column) VALUES (#value)";
var command = new SqlCommand(query, con);
command.Parameters.Add("#value", value);
command.ExecuteNonQuery();
command.Parameters.Clear();
command.CommandText = "SELECT ##IDENTITY";
int identity = Convert.ToInt32(command.ExecuteScalar());
}

Proper SQL query command with SQL Compact is failing

I've got a function that stores temporary information generated for every user authenticated in the system. This 'session ID' is a string stored in a Sessions table, along the original ID of the user which authenticated and was given said session identifier.
The function to remove/deauthenticate/invalidate an existing session first checks if the user exists through another method implemented as follows:
int userId = 0;
SqlCeCommand cmd = new SqlCeCommand();
SqlCeParameterCollection sqlParams = cmd.Parameters;
sqlParams.AddWithValue("#User", userName);
cmd.Connection = this.conn;
cmd.CommandText = "SELECT Id FROM Users WHERE (Username = #User)";
userId = (int) cmd.ExecuteScalar()
cmd.Dispose();
Afterwards it tries to find an existing session for that user, which is to be removed (via a different method again):
SqlCeCommand cmd = new SqlCeCommand();
SqlCeParameterCollection sqlParams = cmd.Parameters;
sqlParams.AddWithValue("#SID", mysession);
sqlParams.AddWithValue("#UID", myuserid);
cmd.Connection = this.Connection;
cmd.CommandText = "SELECT Id FROM UserSessions WHERE (SessionID = #SID) AND (User_Id = #UID)";
int foo = cmd.ExecuteNonQuery();
...which fails. No exception is raised unfortunately. So I added an insecure equivalent using a non parametrized query string:
cmd.CommandText = String.Format("SELECT Id FROM UserSessions WHERE (SessionID = '{0}') AND (User_Id = {1})", mysession, myuserid);
cmd.Prepare();
int bar = cmd.ExecuteNonQuery();
Added a breakpoint, paused, copy pasted the query into the Visual Studio Query tool and voila, it indeed worked. But after continuing, that query in the code failed as well. I'm unable to find the culprit of this annoying issue since no exception is raised and everything seems correct. The data exists, the parameters are provided in proper types (string and int) and I'm out of things to check. The connection is open and so forth.
Any clues from anyone around? Thanks!
Update: Mea culpa, missed the fact that the function used ExecuteScalar until I modified it for testing. It does use ExecuteScalar and returns null, just in case.
You're using ExecuteNonQuery:
int foo = cmd.ExecuteNonQuery();
... but you're clearly trying to execute a query (a SELECT)! Use ExecuteScalar again, as you did in the first code, or ExecuteReader and look through the results appropriately. If you stick with ExecuteScalar, you should first check whether the result is null to indicate no results.
ExecuteNonQuery returns the number of rows affected by an UPDATE/INSERT/DELETE command - which is what it's intended for. I suspect it's returning -1 for you, as documented:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
(Emphasis mine.)
Use set [] to avoid ambiguity with database keyword.
cmd.CommandText = "SELECT [Id] FROM [Users] WHERE ([Username] = #User)";
and use ExecuteScalar() or ExecureReader() method when working with SELECT statements.

Categories