SQL query execution order error - c#

Starting to learn sql and having trouble with my query. I have - 2 tables calendar and activities and FK table DateActivities. Got 2 simple lists calendar with dates and activities. I want to be able with a button click to enter new activity through text box on selected date. But when I do that I get error on a query. Thanks for your help.
private void btnAddToDate_Click(object sender, EventArgs e)
{
string query = "DECLARE #ActivitiesId TABLE (Id INT) " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName) " +
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivitiesId)";
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
command.Parameters.AddWithValue("#ActivitiesName", textDate.Text);
command.Parameters.AddWithValue("#CalendarId", listCalendar.SelectedValue);
command.ExecuteNonQuery();
}
FillCalendar();
FillActivities();
}

You are trying to execute multiple statement and thus need to separate them with ; as line terminator like below else it's treated as single statement to execute. If you just copy/paste the statement block in SSMS you will get the same error.
"DECLARE #ActivitiesId TABLE (Id INT); " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName); " +
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivitiesId)"
You should better pull this off to a stored procedure instead running as adhoc query.

You are inserting whole table in the column value of DateActivities which is obviously wrong and will fail, you need to use another variable to hold the ActivityId and then insert it next, see below:
"DECLARE #ActivitiesId TABLE (Id INT)
DECLARE #ActivityId INT " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName) " +
"SELECT #ActivityId = Id from #ActivitiesId"
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivityId)";

Related

Why is my call to LastInsertedId not returning the expected value?

I have MySql Tables with autoinc ID columns, such as "director_id" here:
CREATE TABLE directors (
director_id Integer NOT NULL AUTO_INCREMENT,
first_name VarChar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
middle_name VarChar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
last_name VarChar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
suffix VarChar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
PRIMARY KEY (
director_id
)
)
I want to store the autoincremented director_id value in the movies_main Table.
So I try to assign the autoincremented value to an int variable:
long director_id = 0;
...in the call to LastInsertedId here (last line):
if (!alreadyExists)
{
comm.Parameters.Clear();
comm.CommandText = "INSERT INTO Directors " +
"(first_name, middle_name, last_name, suffix) " +
"VALUES " +
"(#first_name, #middle_name, #last_name, #suffix)";
comm.Parameters.AddWithValue("#first_name", directorNamePartsList[0]);
comm.Parameters.AddWithValue("#middle_name", directorNamePartsList[1]);
comm.Parameters.AddWithValue("#last_name", directorNamePartsList[2]);
comm.Parameters.AddWithValue("#suffix", directorNamePartsList[3]);
comm.ExecuteNonQuery();
director_id = comm.LastInsertedId;
}
...and then assign it to the movies_main Table like so:
if (!alreadyExists)
{
comm.Parameters.Clear();
comm.CommandText = "INSERT INTO Movies_Main " +
"(movie_title, mpaa_rating, imdb_rating, movie_length, director_id,
screenwriter_id, year_released) " +
"VALUES " +
"(#movie_title, #mpaa_rating, #imdb_rating, #movie_length, #director_id,
#screenwriter_id, #year_released)";
comm.Parameters.AddWithValue("#movie_title", title);
comm.Parameters.AddWithValue("#mpaa_rating", mpaa_rating);
comm.Parameters.AddWithValue("#imdb_rating", Math.Round(imdb_rating, 1));
comm.Parameters.AddWithValue("#movie_length", movie_length);
comm.Parameters.AddWithValue("#director_id", director_id);
comm.Parameters.AddWithValue("#screenwriter_id", screenwriter_id);
comm.Parameters.AddWithValue("#year_released", year_released);
comm.ExecuteNonQuery();
movie_id = comm.LastInsertedId;
}
Yet the value assigned to the movies_main Table for director_id is always 0!
Why is LastInsertId (apparently) returning 0, and how can I get it to actually return the value its name claims it does? Will I have to resort to a "SELECT MAX(director_id)" query to actually get the value?
NOTE: The movie_id code does work! I get a non-zero value when assigning the result of the call to LastInsertedId to the movie_id variable, and it is added to other tables just fine. This code works as expected:
foreach (var gen_desc in genreList)
{
long genreID = Convert.ToInt32(GetGenreIDForDescription(gen_desc));
alreadyExists = PairAlreadyExistsInMoviesGenresM2Mtable(
movie_id, genreID);
if (!alreadyExists)
{
comm.Parameters.Clear();
comm.CommandText = "INSERT INTO Movies_Genres " +
"(movie_id, genre_id) " +
"VALUES " +
"(#movie_id, #genre_id)";
comm.Parameters.AddWithValue("#movie_id", movie_id);
comm.Parameters.AddWithValue("#genre_id", genreID);
comm.ExecuteNonQuery();
}
}
An alternative way to LastInsertedId property from the MySqlCommand is the native MySql function LAST_INSERT_ID. We can call this function and get its return value adding a simple SELECT statement to your current command text. MySql supports batch statements and so, with a single server call we could execute more than one single command text.
if (!alreadyExists)
{
comm.Parameters.Clear();
comm.CommandText = "INSERT INTO Directors " +
"(first_name, middle_name, last_name, suffix) " +
"VALUES " +
"(#first_name, #middle_name, #last_name, #suffix); " + // semicolon to close the first statement
"SELECT LAST_INSERT_ID()";
comm.Parameters.AddWithValue("#first_name", directorNamePartsList[0]);
comm.Parameters.AddWithValue("#middle_name", directorNamePartsList[1]);
comm.Parameters.AddWithValue("#last_name", directorNamePartsList[2]);
comm.Parameters.AddWithValue("#suffix", directorNamePartsList[3]);
director_id = Convert.ToInt64(comm.ExecuteScalar());
}
Note that we can now use ExecuteScalar because we get back just one record with a single column.
Let me say however that I have tried to reproduce your problem with LastInsertedId. I have recreated your table and written a simple script in LinqPad trying to insert some fixed data in that table.
I have no problem with LastInsertedId property and I get the correct value. I have read that if you have more threads that are concurrently inserting records you could get some problems with that property but I have no proof of any kind of misbehaving

My query keeps rubbish in my sql table if it will not be complete properly

I'm using a a multiple query with insert and update statement together.
The problem is that if query will not be completed(for some reason e.x bad internet connection) my SQL Server table keeps rubbish.
Example of query:
SqlCommand cmd = new SqlCommand("INSERT INTO CustomerTrans (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime) SELECT " + Connection.TableName + ",' " + Connection.UserID + "', '" + Connection.Username + "',Sum(Quantity),Sum(Price),Sum(RealPrice),Sum(ExtrasPrice), Sum(Quantity * Price),Sum(Quantity * DiscountPrice),'" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' from InventoryTransTemp where active=1 and TableName=" + Connection.TableName + ";update InventorytransTemp set TrnDocumentID=(select max(TrnDocumentID) from CustomerTrans where UserID='" + Connection.UserID + "'),Active=0 where TableName=" + Connection.TableName + " and Active=1", con);
cmd.ExecuteNonQuery();
Take a photo from a query which has not be completed properly look query 2989 it has NULL values. I want to avoid inserting something if query is not be completed properly.
Sorry for my previous Question it was Unclear
Try it like this:
string sql =
"INSERT INTO CustomerTrans" +
" (TableName, UserID, UserName, SumQuantity, SumPrice, SumRealPrice, SumExtrasPrice, SumTotal, SumDiscountTotal, DateTime)" +
" SELECT #TableName, #UserID, #Username, Sum(Quantity), Sum(Price), Sum(RealPrice), Sum(ExtrasPrice), Sum(Quantity * Price), Sum(Quantity * DiscountPrice), current_timestamp" +
" FROM InventoryTransTemp" +
" WHERE active=1 and TableName= #TableName;\n" +
"SELECT #TranID = scope_identity;\n"
"UPDATE InventorytransTemp" +
" SET TrnDocumentID=#TranID ,Active=0" +
" WHERE TableName= #Tablename and Active=1;";
using (var con = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, con))
{
//I'm guessing at exact column types/lengths here.
// You should update this to use your exact column types and lengths.
// Don't let ADO.Net try to guess this for you.
cmd.Parameters.Add("#TableName", SqlDbType.NVarChar, 20).Value = Connection.TableName;
cmd.Parameters.Add("#UserID", SqlDbType.Int).Value = Connection.UserID;
cmd.Parameters.Add("#Username", SqlDbType.NVarChar, 20).Value = Connection.Username;
cmd.Parameters.Add("#TranID", SqlDbType.Int).Value = 0; //placeholder only
con.Open();
cmd.ExecuteNonQuery();
}
Note the improved formatting of the query, the use of scope_identity() to get the new identity value rather than a nested select statement that might not be atomic, that I avoided ALL uses of string concatenation to substitute data into the query, that I avoided the AddWithValue() method entirely in favor of an option that doesn't try to guess at your parameter types, and the use of using blocks to be sure the SqlClient objects are disposed properly.
The only thing I'm still concerned about is if your INSERT/SELECT operation might create more than one new record. In that case, you'll need to handle this a different way that probably involves explicit BEGIN TRANSACTION/COMMIT statements, because this code only gets one #TranID value. But in that case, the original code was broken, too.

Create a MySQL sproc from c#, delimiter issues

I'm trying to create stored procedures from a c# program. It typically reads the sproc definition from a text file, and then run it against the chosen database.
My SQL script file looks like this:
DROP PROCEDURE IF EXISTS MySproc;
DELIMITER //
CREATE PROCEDURE MySproc(
IN Id BIGINT,
IN Reference VARCHAR(255),
IN Bla VARCHAR(255)
)
BEGIN
INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference);
INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla);
END
//
DELIMITER ;
and this works fine in the workbench.
I then execute it with this type of c# code:
using (MySqlCommand sqlCommand = _mySqlConnection.CreateCommand())
{
sqlCommand.Connection = _mySqlConnection;
sqlCommand.CommandText = scriptfile;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.ExecuteNonQuery();
}
And it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //
CREATE PROCEDURE MySproc( IN Id BIGINT
' at line 1
If I remove the DELIMITER // stuff, then it still parses the semi colons between BEGIN and END as a delimiter for the outer statement, and it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 31
Any idea how I can set either the Command or the something int he script so that it works? Not even sure if the error actually comes from MySQL itself, or from the MySqlCommand library (MySql.Data.6.9.9). And MySQL server is 5.6.25, InnoDB tables.
Can you try replacing the DELIMITER // with something like delimiter $$
Pointless question, sorry, it's embarrassing. This morning, I created a unit test following the top part of this page: https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
and it works fine:
[TestMethod]
public void TestSprocCreationFromMySqlDoc()
{
// from https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
MySqlConnection conn = new MySqlConnection();
conn.ConnectionString = "server=localhost;user=root;database=test;port=3306;password=;";
MySqlCommand cmd = new MySqlCommand();
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "DROP TABLE IF EXISTS emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE PROCEDURE add_emp(" +
"IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" +
"BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
"VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";
cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
Then, I did another test with my own statements (trying to replicate file read from disk, with crlf) and it works too!
cmd.CommandText =
"DROP PROCEDURE IF EXISTS MySproc; " + Environment.NewLine +
"CREATE PROCEDURE MySproc(" + Environment.NewLine +
"IN Id BIGINT," + Environment.NewLine +
"IN Reference VARCHAR(255)," + Environment.NewLine +
"IN Bla VARCHAR(255))" + Environment.NewLine +
"BEGIN " + Environment.NewLine +
"INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference); " + Environment.NewLine +
"INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla); " + Environment.NewLine +
"END";
cmd.ExecuteNonQuery();
And then I ran my original application (that read scripts from files) and it runs ok as well! So I can't explain it. I'm wondering if I did something to the MySql server that affected all connections, or did something in one connection that stayed on, affecting all connections, until a reboot.

c# Insert boolean value into database

I have problem inserting boolean value into database.
I have simple structure:
struct
{
string name;
bool isStudent;
}
and I want to insert it into data base like this:
dbCommand.CommandText = "INSERT INTO People (name, isStudent) VALUES ('" + people1.name + "', " + people1.isStudent + ")";
dbCommand.ExecuteNonQuery();
but i throws exception:
SQLite error no such column: True
Try using:
dbCommand.CommandText = "INSERT INTO People (name, isStudent) VALUES ('" + people1.name + "', '" + people1.isStudent + "')";
Note that 'true' or 'false' will be quoted this way.
Or:
int val = isStudent ? 1 : 0;
dbCommand.CommandText = "INSERT INTO People (name, isStudent) VALUES ('" + people1.name + "', " + val + ")";
1 will be used for true values and 0 for false values.
Use parameters and you won't have to worry about quotes or format of the values (besides, it is a good practice to avoid SQL injection):
dbCommand.CommandText = "INSERT INTO People (name, isStudent)
VALUES (#name, #isStudent)";
dbCommand.Parameters.AddWithValue("#name", people1.name);
dbCommand.Parameters.AddWithValue("#isStudent", people1.isStudent);
dbCommand.ExecuteNonQuery();
SQLite doesn't have a bool column type and you're constructing the SQL statement yourself. If you want to do that, then convert 1 and 0 back and forth.
I would also think the .net wrapper would do that 4 u. But you would have to use SQL parameters and not build the string yourself to even give it a chance to do that.
Building parameterized queries (?) also let's SQL lite cache the compiled statements.

join for insert statement mysql syntax

hey I have two tables and Im looking to make a mysql sytax statement for insert:
Table structure:
Im trying to insert userid and picturepath (which i can do) but how would I insert into flag in the user table aswell in the same insert syntax:
("INSERT INTO Pictures (UserID, picturepath) VALUES (" + theUserId + ", '" + fileuploadpaths + "')", cn);
theuserid is set by a session so I can reuse the string for that to know which coloum to insert into the user.
gonna have to do an update statment after the insert statement
("INSERT INTO Pictures (UserID, picturepath) VALUES (" + theUserId + ", '" + fileuploadpaths + "') "+
"GO UPDATE user SET flag = 1 WHERE UserID = "+theUserId+" GO", cn);
might work
try to execute this command in sql management if you have it with test data to make sure it allows this to work like this

Categories

Resources