Insert and Update mysql values c# - c#

I use this code in my twitch bot to count messages and save them to a database a couple times per minute.
So the current code I have does get the values I want from my database, but I cannot update or insert the values correctly. The insert_cmd does execute, but values in the database does not correspond to the values I try to insert.
affectedRows does return the correct answer of rows that should have been affected. Also when I write out the insert_cmd string, it does look right.
private static void update_messages()
{
try
{
MySql.Data.MySqlClient.MySqlConnection mysql_connection = new MySql.Data.MySqlClient.MySqlConnection();
mysql_connection.ConnectionString = mysql_connection_string;
mysql_connection.Open();
//build query string
string select_cmd = "SELECT * FROM taperen.messages where username in (";
foreach(CountData cd in chat_messages)
{
//Console.WriteLine(cd.username);
select_cmd += "\'" + cd.username + "\',";
}
if(select_cmd == "SELECT * FROM taperen.messages where username in (")
{
mysql_connection.Close();
return;
}
select_cmd = select_cmd.TrimEnd(select_cmd[select_cmd.Length - 1]);
select_cmd += ");";
//Console.WriteLine(select_cmd);
MySql.Data.MySqlClient.MySqlCommand myCommand = mysql_connection.CreateCommand();
myCommand.CommandText = select_cmd;
MySql.Data.MySqlClient.MySqlDataReader reader = myCommand.ExecuteReader();
string insert_cmd = "";
while (reader.Read())
{
string username = reader["username"].ToString();
int index = chat_messages.FindIndex(x => x.username.Equals(username));
int current_online_count = chat_messages[index].online_count;
int current_offline_count = chat_messages[index].offline_count;
int db_online_count = (int)reader["online_count"];
int db_offline_count = (int)reader["offline_count"];
int new_online_count = current_online_count + db_online_count;
int new_offline_count = current_offline_count + db_offline_count;
insert_cmd += $"UPDATE `taperen`.`messages` SET `online_count`='{new_online_count}', `online_count`='{new_offline_count}' WHERE `id`='{reader["id"]}';";
chat_messages.RemoveAt(index);
//Console.WriteLine(username);
}
reader.Close();
mysql_connection.Close();
foreach(CountData cd in chat_messages)
{
insert_cmd += $"INSERT INTO `taperen`.`messages` (`username`, `online_count`, `offline_count`) VALUES ('{cd.username}', '{cd.online_count}', '{cd.offline_count}');";
}
mysql_connection.Open();
//Console.WriteLine(insert_cmd);
myCommand.CommandText = insert_cmd;
int affectedRows = myCommand.ExecuteNonQuery();
Console.WriteLine(affectedRows);
myCommand.Dispose();
mysql_connection.Close();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
Console.WriteLine(ex.Message);
}
}
The CountData class looks like this:
public class CountData
{
public string username { get; set; }
public int online_count { get; set; }
public int offline_count { get; set; }
}
The database looks like this:
Also if I do something else stupid in my code I appreciate if you could come with some tips :)

In this line you are setting online_count twice, the second instance should (presumably) be offline_count.
insert_cmd += $"UPDATE taperen.messages SET online_count='{new_online_count}', online_count='{new_offline_count}' WHERE id='{reader["id"]}';";

You need to pick out the query generated by your code. And then directly run it into Mysql and then compare what it is returning. It looks mysql return effected rows of last executing query. As you are combining Update first and then Insert, hence the effected rows which are getting for Insert. But you can confirm it by directly running your query. Be sure to comment out the code like this :
// int affectedRows = myCommand.ExecuteNonQuery();

Related

No current row message appears while getting Max values from SQLite database

I want to get max value form database if database not empty. Program works fine but it gives No Current Row message on start. I've query like this,
public int GetMaxValue(String table, String column, int columnIndex)
{
try
{
int values = -1;
String query = "SELECT MAX(" + column + ") FROM " + table;
SQLiteCommand sQLiteCommand = new SQLiteCommand(query, sQLiteConnection);
sQLiteCommand.ExecuteNonQuery();
using (SQLiteDataReader sQLiteDataReader = sQLiteCommand.ExecuteReader())
{
if (!sQLiteDataReader.IsDBNull(0))
{
while (sQLiteDataReader.Read())
{
values = sQLiteDataReader.GetInt32(columnIndex);
sQLiteDataReader.Close();
return values;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return -1;
}
and call this method by,
string orderNo = database.GetMaxValue(Database.TABLE_ORDER, Database.INVOICE_NO_ORDER, 0).ToString();
in above function, i've check already if Reader Null then do not continue by this,
if (!sQLiteDataReader.IsDBNull(0))
}
but its not works. Kindly tell how to get rid of No Current Row message
This solve my problem
public Int32 GetMaxValue(String table, String column, int columnIndex)
{
try
{
Int32 values = -1;
String query = "SELECT MAX(" + column + ") FROM " + table;
SQLiteCommand sQLiteCommand = new SQLiteCommand(query, sQLiteConnection);
sQLiteCommand.ExecuteScalar();
using (SQLiteDataReader sQLiteDataReader = sQLiteCommand.ExecuteReader())
{
if (sQLiteDataReader.Read())
{
while (sQLiteDataReader.Read())
{
values = sQLiteDataReader.GetInt32(columnIndex);
return values;
}
}
sQLiteDataReader.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return -1;
}

Error inserting a record and retrieving the autonumeric ID with OleDb

I am trying to make an oledb connection to an Access database to insert a new record and retrieving the key generated all at once. The code is this:
private static int createUser(OleDbConnection accessConn)
{
try
{
accessConn.Open();
//DbCommand also implements IDisposable
using (OleDbCommand cmd = accessConn.CreateCommand())
{
//create command with placeholders
cmd.CommandText =
"INSERT INTO EmployeeFiles " +
"([FirstName], [LastName], [JobTitleID], [SecurityLevel], [RowGUID])" +
"VALUES(#FirstName, #LastName, #JobTitleID, #SecurityLevel, #RowGUID)";
//Set Parameters
string FirstName = "Dick";
string LastName = "Tracy";
int JobTitleID = 11;
string SecurityLevel = "1";
string RowGUID = "{" + Guid.NewGuid() + "}";
//add named parameters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#FirstName", FirstName),
new OleDbParameter("#LastName", LastName),
new OleDbParameter("#JobTitleID", JobTitleID),
new OleDbParameter("#SecurityLevel", SecurityLevel),
new OleDbParameter("#RowGUID", RowGUID)
});
int userId = 0;
//Add #EmployeeID to the params collection and then retrieve it with Value
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
userId = (int)cmd.Parameters["#EmployeeID"].Value;
//userId = (int)cmd.ExecuteScalar();
Console.WriteLine("user created successfully: {0}", deliveryId);
return userId;
}
}
catch (Exception ex)
{
Console.WriteLine("Error: Failed creating the user.\n{0}", ex.Message);
return 0;
}
finally
{
accessConn.Close();
}
}
And when I run the code it throws this error:
System.Data.OleDb.OleDbDataAdapter internal error: invalid parameter accessor: 9 BADBINDINFO
I'm pretty sure the problematic line is this:
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
And I just don't get where is the mistake.
If I comment that and the next two lines, and uncomment this:
userId = (int)cmd.ExecuteScalar();
It throws the error: Object reference not set to an instance of an object
Is there a way to get this working with OleDbParameter? So far I'm being forced to make the insert and then a select to get the key generated.
I appreciate any suggestion.

C# Fatal error encoutered during data read

I'm selecting about 20,000 records from the database and then I update them one by one.
I looked for this error and I saw that setting the CommandTimeout will help, but not in my case.
public void Initialize()
{
MySqlConnectionStringBuilder SQLConnect = new MySqlConnectionStringBuilder();
SQLConnect.Server = SQLServer;
SQLConnect.UserID = SQLUser;
SQLConnect.Password = SQLPassword;
SQLConnect.Database = SQLDatabase;
SQLConnect.Port = SQLPort;
SQLConnection = new MySqlConnection(SQLConnect.ToString());
}
public MySqlDataReader SQL_Query(string query)
{
MySqlCommand sql_command;
sql_command = SQLConnection.CreateCommand();
sql_command.CommandTimeout = int.MaxValue;
sql_command.CommandText = query;
MySqlDataReader query_result = sql_command.ExecuteReader();
return query_result;
}
public void SQL_NonQuery(string query)
{
MySqlCommand sql_command;
sql_command = SQLConnection.CreateCommand();
sql_command.CommandTimeout = int.MaxValue;
sql_command.CommandText = query;
sql_command.ExecuteNonQuery();
}
And here is my method which makes the select query:
public void CleanRecords()
{
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while(cashData.Read()){
if(cashData["income_money"].ToString() == cashData["total"].ToString()){
UpdateRecords(cashData["id"].ToString());
}
}
SQLActions.SQL_Close();
}
And here is the method which makes the update:
public void UpdateRecords(string rowID)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id`='" + rowID + "'");
SQLActions.SQL_Close();
}
Changing the database structure is not an option for me.
I thought that setting the timeout to the maxvalue of int will solve my problem, but is looks like this wont work in my case.
Any ideas? :)
EDIT:
The error which I get is "Fatal error encoutered during data read".
UPDATE:
public void CleanRecords()
{
StringBuilder dataForUpdate = new StringBuilder();
string delimiter = "";
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while (cashData.Read())
{
if (cashData["income_money"].ToString() == cashData["total"].ToString())
{
dataForUpdate.Append(delimiter);
dataForUpdate.Append("'" + cashData["id"].ToString() + "'");
delimiter = ",";
}
}
SQLActions.SQL_Close();
UpdateRecords(dataForUpdate.ToString());
}
public void UpdateRecords(string rowID)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowID + ")");
SQLActions.SQL_Close();
}
You may be able to use
UPDATE cash_data .... WHERE id IN (SELECT ....)
and do everything in one go. Otherwise, you could do it in two steps: first the select collects all the ids, close the connection and then do the update in obne go with all the ids.
The code for the second option might look something like this:
public void CleanRecords()
{
StringBuilder builder = new StringBuilder();
string delimiter = "";
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while(cashData.Read()){
if(cashData["income_money"].ToString() == cashData["total"].ToString()){
builder.Append(delimiter);
builder.Append("'" + cashData["id"].ToString() + "'");
delimiter = ",";
}
}
SQLActions.SQL_Close();
UpdateRecords(builder.ToString());
}
public void UpdateRecords(string rowIDs)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowIDs + ")";
SQLActions.SQL_Close();
}
There are multiple problem:
First: You have reading information around 20K using data reader and then doing update one by one in reader itself. Reader holds the connection open until you are finished. So this is not the good way to do it. Solution: We can read the information using Data Adapter.
Second: Rather than doing one by one update, we can update in bulk in one go. There are multiple option for bulk operation. In SQL u can do either by sending information in XML format or u can use Table Valued Parameter (TVP) (http://www.codeproject.com/Articles/22205/ADO-NET-and-OPENXML-to-Perform-Bulk-Database-Opera) OR (http://dev.mysql.com/doc/refman/5.5/en/load-xml.html)

SQL Syntax Error (INSERT command)

I have a form with a text box and button, such that when the user clicks the button, the specified name in the text box is added to a table in my sql database. The code for the button is as follows:
private void btnAddDiaryItem_Click(object sender, EventArgs e)
{
try
{
string strNewDiaryItem = txtAddDiaryItem.Text;
if (strNewDiaryItem.Length == 0)
{
MessageBox.Show("You have not specified the name of a new Diary Item");
return;
}
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES = ('" + strNewDiaryItem + "');";
cSqlQuery cS = new cSqlQuery(sqlText, "non query");
PopulateInitialDiaryItems();
MessageBox.Show("New Diary Item added succesfully");
}
catch (Exception ex)
{
MessageBox.Show("Unhandled Error: " + ex.Message);
}
}
The class cSqlQuery is a simple class that executes various T-SQL actions for me and its code is as follows:
class cSqlQuery
{
public string cSqlStat;
public DataTable cQueryResults;
public int cScalarResult;
public cSqlQuery()
{
this.cSqlStat = "empty";
}
public cSqlQuery(string paramSqlStat, string paramMode)
{
this.cSqlStat = paramSqlStat;
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
if (paramMode == "non query")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
sqlCom.ExecuteNonQuery();
linkToDB.Close();
}
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(cSqlStat, linkToDB))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
this.cScalarResult = (Int32)sqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public cSqlQuery(SqlCommand paramSqlCom, string paramMode)
{
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
paramSqlCom.Connection = linkToDB;
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(paramSqlCom))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
paramSqlCom.Connection = linkToDB;
this.cScalarResult = (Int32)paramSqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public string BuildConnectionString()
{
cConnectionString cCS = new cConnectionString();
return cCS.strConnect;
}
}
The class works well throughout my application so I don't think the error is in the class, but then I can't be sure.
When I click the button I get the following error message:
Incorrect syntax near =
Which is really annoying me, because when I run the exact same command in SQL Management Studio it works fine.
I'm sure I'm missing something rather simple, but after reading my code through many times, I'm struggling to see where I have gone wrong.
you have to remove = after values.
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES ('" + strNewDiaryItem + "');"
and try to use Parameterized queries to avoid Sql injection. use your code like this. Sql Parameters
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES (#DairyItem);"
YourCOmmandObj.Parameters.AddwithValue("#DairyItem",strNewDiaryIItem)
Remove the = after VALUES.
You do not need the =
A valid insert would look like
INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)
Source: http://www.w3schools.com/sql/sql_insert.asp
Please use following:
insert into <table name> Values (value);
Remove "=", and also i would recommend you to use string.format() instead of string concatenation.
sqlText = string.format(INSERT INTO tblDiaryTypes (DiaryType) VALUES ('{0}'), strNewDiaryItem);"

What's wrong with my IF statement?

I'm creating an auditting table, and I have the easy Insert and Delete auditting methods done. I'm a bit stuck on the Update method - I need to be able to get the current values in the database, the new values in the query parameters, and compare the two so I can input the old values and changed values into a table in the database.
Here is my code:
protected void SqlDataSource1_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
string[] fields = null;
string fieldsstring = null;
string fieldID = e.Command.Parameters[5].Value.ToString();
System.Security.Principal. WindowsPrincipal p = System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
string[] namearray = p.Identity.Name.Split('\\');
string name = namearray[1];
string queryStringupdatecheck = "SELECT VAXCode, Reference, CostCentre, Department, ReportingCategory FROM NominalCode WHERE ID = #ID";
string queryString = "INSERT INTO Audit (source, action, itemID, item, userid, timestamp) VALUES (#source, #action, #itemID, #item, #userid, #timestamp)";
using (SqlConnection connection = new SqlConnection("con string = deleted for privacy"))
{
SqlCommand commandCheck = new SqlCommand(queryStringupdatecheck, connection);
commandCheck.Parameters.AddWithValue("#ID", fieldID);
connection.Open();
SqlDataReader reader = commandCheck.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount - 1; i++)
{
if (reader[i].ToString() != e.Command.Parameters[i].Value.ToString())
{
fields[i] = e.Command.Parameters[i].Value.ToString() + "Old value: " + reader[i].ToString();
}
else
{
}
}
}
fieldsstring = String.Join(",", fields);
reader.Close();
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#source", "Nominal");
command.Parameters.AddWithValue("#action", "Update");
command.Parameters.AddWithValue("#itemID", fieldID);
command.Parameters.AddWithValue("#item", fieldsstring);
command.Parameters.AddWithValue("#userid", name);
command.Parameters.AddWithValue("#timestamp", DateTime.Now);
try
{
command.ExecuteNonQuery();
}
catch (Exception x)
{
Response.Write(x);
}
finally
{
connection.Close();
}
}
}
The issue I'm having is that the fields[] array is ALWAYS null. Even though the VS debug window shows that the e.Command.Parameter.Value[i] and the reader[i] are different, the fields variable seems like it's never input into.
Thanks
You never set your fields[] to anything else than null, so it is null when you are trying to access it. You need to create the array before you can assign values to it. Try:
SqlDataReader reader = commandCheck.ExecuteReader();
fields = new string[reader.FieldCount]
I don't really understand what your doing here, but if your auditing, why don't you just insert every change into your audit table along with a timestamp?
Do fields = new string[reader.FieldCount] so that you have an array to assign to. You're trying to write to null[0].

Categories