I have been trying to add the Customer_ID from the Customer table to Customer_ID in Customer_Ship table. I keep running into the Customer_ID not converting to Int properly. It's possible that I am not actually getting the new row added to Customer_Ship table first. Your help is greatly appreciated and many thanks in advance.
if (customer_ID == "")
{
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 customer_Id = (int)sqlCommand.ExecuteScalar();
SQL = "INSERT INTO Customer_Ship (Customer_ID) VALUES (#customer_Id)";
sqlCommand = new SqlCommand(SQL, sqlConnection);
sqlCommand.Parameters.AddwithValue("#customer_Id", customer_Id);
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
}
Two mistakes I see:
you should be just returning SCOPE_IDENTITY - you can simplify your first INSERT statement to read:
INSERT INTO Customer (Customer_Name) VALUES (#customer_Name); SELECT SCOPE_IDENTITY();";
This will return the newly inserted Customer_ID identity value from the Customer table - no need to do this complicated SELECT that you had in your question
You need to call .ExecuteScalar() right from the beginning - don't call .ExecuteNonQuery() first and then ExecuteScalar() - that'll execute the statement twice - just use:
using(SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection))
{
sqlCommand.Parameters.Add("#customer_Name", SqlDbType.VarChar, 100).Value = customer_Name;
sqlConnection.Open();
int customer_Id = (int)sqlCommand.ExecuteScalar();
sqlConnection.Close();
}
That'll insert the values into Customer and return the newly created Customer_ID as the return value into customer_id (which already is an Int) from .ExecuteScalar(). You can then use this int value to insert into the Customer_Ship table - no conversion necessary - this already is an int
The possible reason for not converting the value is you are trying to convert an empty string(customer_ID : Refer Line :#1 of your code) and not "customer_Id " what you are fetching from the database .
Related
I have two tables FILM(Id, Title, Director, Year, Category) and Record(Id, Film_id)
Id from FILM table is used as a foreign key as Film_id in Record table.
I want to insert data at the same time date into both tables. How construct a sql query with INSERT?
using (var connection = new MySqlConnection(constring))
{
connection.Open();
using (var cmdDataBase = connection.CreateCommand())
{
cmdDataBase.CommandText = "INSERT INTO film(Title, Director, Year, Category) VALUES (#Title, #Director, #Year, #Category) ";
cmdDataBase.Parameters.Add(new MySqlParameter("#Title", fm.Title));
cmdDataBase.Parameters.Add(new MySqlParameter("#Director", fm.Director));
cmdDataBase.Parameters.Add(new MySqlParameter("#Year", fm.Year));
cmdDataBase.Parameters.Add(new MySqlParameter("#Category",n));
cmdDataBase.ExecuteNonQuery();
}
}
You get the last auto-generated ID with LAST_INSERT_ID(). Then, you'd use a transaction, because you don't want to insert a parent record, if you can't also insert the child record, or so I understand.
This is it more or less. You should add error handling (try, catch) of course.
// Start transaction
MySqlTransaction transaction = connection.BeginTransaction();
MySqlCommand command = new MySqlCommand();
command.Connection = connection;
command.Transaction = transaction;
// Parent record
command.CommandText = "INSERT INTO film(Title, Director, Year, Category) VALUES (#Title, #Director, #Year, #Category) ";
command.Parameters.Add(new MySqlParameter("#Title", fm.Title));
command.Parameters.Add(new MySqlParameter("#Director", fm.Director));
command.Parameters.Add(new MySqlParameter("#Year", fm.Year));
command.Parameters.Add(new MySqlParameter("#Category",n));
command.ExecuteNonQuery();
// Child record
command.CommandText = "INSERT INTO record (Film_id) VALUES (LAST_INSERT_ID())";
command.ExecuteNonQuery();
// Commit inserts
transaction.Commit();
You need to do it in sequence. First, add record to your main table Film, then other table Record. Check below:
INSERT INTO Film(Title, Director, Year, Category)
VALUES('Title', 'DirectorName', 1990, 'Action');
--Assuming ID for Record table is AUTO_INCREMENT column
INSERT INTO Record(Film_id)
VALUES ((SELECT id FROM Film WHERE Title='Title' and Director='Director'));
Also, LAST_INSERT_ID() can be used:
INSERT INTO Film
...
INSERT INTO Record
...
film_id = LAST_INSERT_ID()
Ref: Mysql: How to insert values in a table which has a foreign key
If you are using MySQL try to add ;return LAST_INSERT_ID(); at the end of you query and add return parameter as below.
var returnVal = cmdDataBase.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnVal.Direction = ParameterDirection.ReturnValue;
After cmdDataBase.ExecuteNonQuery(); extract id from returnVal
var id = returnParameter.Value;
After that you can use id to perform the second insert.
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.
I need to select and Get a single unique value from a table where the key has duplicate entries. For instance there is a Transaction ID(Id) and an AccountNumber(AccountNumber) and for each account number there are many entries but I have to get only the Maximum (Transaction ID)(Id) for a particular AccountNumber. I am usnig the following code but gives me multiple rows in the result. Am I doing it right? There is no syntax error in this code . If I remove GROUP BY it gives an error stating no Group BY Statement.
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConString"].ConnectionString);
con.Open();
DataTable dt = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter("select MAX(Id), Address, AccountNumber, Date, CustomerName, Debit, Credit, Balance from fianlTable WHERE (AccountNumber='"+textBox4.Text+"') ) GROUP BY Id, Address, AccountNumber, Date, CustomerName, Debit, Credit, Balance", con);
sda.Fill(dt);
dataGridView1.DataSource = dt;
If you are interested to know just the MAX of a particular ID for a particular AccountNumber then you don't need the other fields neither the GROUP BY
using(SqlConnection con = new SqlConnection(.....))
using(SqlCommand cmd = new SqlCommand(#"select MAX(Id)
from fianlTable
WHERE AccountNumber=#num"), con)
{
int maxValue = 0;
con.Open();
cmd.Parameters.Add("#num" SqlDbType.NVarChar).Value = textBox4.Text;
object result = cmd.ExecuteScalar();
if(result != null)
maxValue = Convert.ToInt32(result);
}
So there is no need of all the infrastructure required by the SqlDataAdapter but just an SqlCommand, its text and the call to ExecuteScalar. Notice also that disposable objects like the connection and the command are enclosed by a using statement to ensure proper closing and disposing
There is also something else to say here. I don't know the reason behind this code but I hope that is not to get the next ID to assign in an INSERT command. Using MAX for this scenario is wrong because the value returned cannot be trusted in a multiuser environment
If you want max(id) then thsi colunmn don't should be in group by
"select
Id
, Address
, AccountNumber
, Date
, CustomerName
, Debit
, Credit
, Balance
from fianlTable
WHERE id = (select max(id) from fianlTable
WHERE AccountNumber='"+textBox4.Text+"'
GROUP BY AccountNumber);"
Not specific to C# but more SQL based, you can select the records for the Account Number - sorted by TransactionId Desc and Limit the results to 1.
This would look like:
SELECT Id, Address, AccountNumber, Date, CustomerName, Debit, Credit, Balance from fianlTable WHERE (AccountNumber='"+textBox4.Text+"') ORDER BY Id DESC LIMIT 1
BTW Lucas is correct you are risking someone hijacking your code by using the value from the textbox directly in the query :)
I'm developing an ASP.NET MVC Web Application using SQL Server.
I am trying to INSERT a new entry into my database and I don't understand what am I doing wrong.
I get an exception on the line:
command.ExecuteNonQuery();
The code is:
try
{
SqlConnection connection = new SqlConnection(#"Data Source=.\SQLEXPRESS;Initial Catalog=UniversityManager;Integrated Security=True");
using (connection)
{
//SqlCommand command = new SqlCommand(
// "INSERT INTO Students VALUES(#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp);",
// connection);
connection.Open();
String sql = "INSERT INTO Students(Id,Name,Surname,Year,PhoneNumber,Cnp) " +
"VALUES (#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp)";
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.Add("#Id", SqlDbType.Int);
command.Parameters["#Id"].Value = 5;
command.Parameters.Add("#Name", SqlDbType.VarChar);
command.Parameters["#Name"].Value = collection.Name;
command.Parameters.Add("#Surname", SqlDbType.VarChar);
command.Parameters["#Surname"].Value = collection.Surname;
command.Parameters.Add("#Year", SqlDbType.Int);
command.Parameters["#Year"].Value = collection.Year;
command.Parameters.Add("#PhoneNumber", SqlDbType.VarChar);
command.Parameters["#PhoneNumber"].Value = collection.PhoneNumber;
command.Parameters.Add("#Cnp", SqlDbType.VarChar);
command.Parameters["#Cnp"].Value = collection.Cnp;
command.ExecuteNonQuery();
connection.Close();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Thank you!
YEAR is a reserved keyword for Sql Server. So, if you really have a column with that name, then you need to enclose it in square brackets every time you refer to it. Better change that name
String sql = "INSERT INTO Students(Id,Name,Surname,[Year],PhoneNumber,Cnp) " +
"VALUES (#Id, #Name, #Surname, #Year, #PhoneNumber, #Cnp)";
Another possibility is the Id column. If this column has the IDENTITY property set to true, then you should not set a value for it. It is automatically calculated by the database engine.
Looking at your innerexception message, it seems the problem is due to one or more of your parameters contains more text than allowed by the database field size.
You could try something like this (for each varchar parameter)
// Assuming the Name field is defined as varchar(15)
command.Parameters.Add("#Name", SqlDbType.VarChar, 15);
command.Parameters["#Name"].Value = collection.Name;
The String or binary data would be truncated exception means you're trying to insert a value that is too large for one of the columns in your Student table. For example, your Name field has a maximum length of 10 but you're trying to insert a 15 character name.
Check the values you're inserting and see if they're too large for the columns.
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.