So i have a class Take for connecting to mysql. In that class I have a method to call a query to take the last record from mysql table.
public void Balance()
{
string query = "SELECT balance FROM history ORDER BY id DESC LIMIT 1 ";
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
cmd.ExecuteNonQuery();
}
}
In the main form I'm calling that class and that method
take.Balance();
I know, that from code above, i don't get any value but NULL, so i am asking how i can take value from that query and put it in the TextBox in the main form?
Personally, I think you should improve your basic knowledge of programming. There are two big problems in your example code:
You want to get the value, but your function is void, not return anything even set the value to some variable
ExecuteNonQuery is not your case.
For example:
public string Balance()
{
string query = "SELECT balance FROM history ORDER BY id DESC LIMIT 1 ";
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
return cmd.ExecuteScalar();
}
}
Let's have look:
// You probably want to return value: decimal, not void
public decimal Balance() {
// Make sql readable
string query =
#"SELECT balance
FROM history
ORDER BY id DESC
LIMIT 1 ";
// do not cache connection, but create a new one instead
using (MySqlConnection conn = new MySqlConnection(connectionStringHere)) {
conn.Open();
// wrap IDisposable into using
using (MySqlCommand cmd = new MySqlCommand(query, conn)) {
// you want to return values: ExecuteReader (or ExecuteScalar)
// instead of ExecuteNonQuery
using (var reader = cmd.ExecuteReader()) {
if (reader.Read())
return Convert.ToDecimal(reader.GetValue(0));
else
return 0m; // cursor is empty, let's return 0
}
}
}
}
There are two things to consider. First, the query
"SELECT balance FROM history ORDER BY id DESC LIMIT 1"
is a query in the sense that some useful data from the database should be returned, it should not be executed with a the method ExecuteNonQuery, which is intended to return the number of rows affected by a non-query statement. Second, the return type of Balance would have to be changed to some other type than void, say int or something similar, which would have to be returned to the caller.
Related
I have a problem - I want to get value from my SQL Server select but it returns:
System.Data.SqlClient.SqlDataReader
Code:
static SqlConnection sqlconnection = new SqlConnection("Data Source=XXXX;Initial Catalog=XXXX;Integrated Security=True");
static SqlCommand sqlcommand = new SqlCommand("SELECT * FROM XXX where XXX = 'XXXX'", sqlconnection);
public static string DBSQL()
{
// connect to database
sqlconnection.Open();
// execute
SqlDataReader myReader = sqlcommand.ExecuteReader();
// return valueAC
return myReader.ToString();
}
You missed a few steps. Always consult the examples provided by the vendor. In particular you're trying to return the reader itself, but instead you need to read data from it. Something like this:
SqlDataReader myReader = sqlcommand.ExecuteReader();
try
{
if (myReader.HasRows)
{
// What should you do if there's more than one row?
while (myReader.Read())
{
// Which value are you trying to read?
return myReader.GetString(0);
}
}
else
{
// What do you do when no rows are found?
return string.Empty;
}
}
finally
{
// Make sure to close the reader
myReader.Close();
}
Note a few questions in the code comments that are really up to you to answer:
You're selecting potentially zero-to-many records, but trying to return a single value. What do you want/expect to happen when the result count is anything other than 1?
You're doing a SELECT *, which is presumably getting more than one value from the database. Which value are you looking to return? (And why select more than that one?)
You can decide what to do in those various cases. But ultimately when using a DataReader you need to fetch the rows returned.
I am working on a project, so I decided to try some CRUD operations so as to be able to manipulate my database.
I already created a form to insert data into the database and it worked, but I am finding it difficult to create that of read .
public int login(string id, string name)
{
MySqlDataReader dr;
int i = 0;
try
{
string query = "SELECT * FROM `all_data` WHERE admin_ID=#id and admin_Name=#name;
open_conn();
MySqlCommand cmd = new MySqlCommand(query,conn);
cmd.Parameters.AddWithValue("#id", id);
cmd.Parameters.AddWithValue("#name",name);
dr = cmd.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
return i;
}
This is where I got confused, as I want it to read from my database and check if it matches my inputs.
If it matches, then it should perform an action.. maybe show a MessageBox saying "login successful".
First, don't build your query by concatenating the id and name directly. This would introduce a SQL injection vulnerability.
string query = "SELECT * FROM `all_data` WHERE admin_ID='"+id+ "' and admin_Name='"+name+"' ";
Instead, use a parameterized query.
string query = "SELECT * FROM `all_data` WHERE admin_ID=#id and admin_Name=#name";
cmd.Parameters.AddWithValue("#id", id);
cmd.Parameters.AddWithValue("#name",name);
Next, we just need to check if a record matches the inputs.
Thus, we can change the query to below to see how many records match.
string query = "SELECT COUNT(*) FROM `all_data` WHERE admin_ID=#id and admin_Name=#name";
Finally, instead of ExecuteReader() we can use ExecuteScalar() to get the count. If the count is greater than 0, we know that there was a successful match.
int matchingRecords = (int).ExecuteScalar();
if (matchingRecords > 0) {
// Logic for successful match
}
What I am expecting my code to do is gather the top ten records that have an 'I' in the SQLMigrationFl field, and then process those ten records by removing that 'I' value. Below is the portion of code that handles this.
string inProgressQuery = "SELECT TOP 10 IDType, ID, Program, Date, Body,
AcctNo, ANPACAcctID, ANPACClientID, TEAMID,
ImportDate, AnnualReview, TeamGUID,
ANPACClientLastName, ANPACClientFirstName, " +
"PolicyNumber, AccountOwnerLastName,
AccountOwnerFirstName, SCRACF, SCDateTime, NoteID
FROM NoteTable WHERE SQLMigrationFl = ?";
command = new OleDbCommand(inProgressQuery, connection);
command.Parameters.AddWithValue("SQLMigrationFl", "I");
reader = command.ExecuteReader();
if(reader.HasRows)
{
while(reader.Read())
{
//clear the In Progress flag
query = "UPDATE NoteTable SET SQLMigrationFl = ? WHERE
NoteTable.NoteID = " + reader[19].ToString();
command = new OleDbCommand(query, connection);
command.Parameters.AddWithValue("SQLMigrationFl", DBNull.Value);
reader = command.ExecuteReader();
}
}
What I am finding is that the query returns one value, and processes it. Then in five seconds it finds another record and reprocesses that one. *Five seconds is just a delay we have set in code to check for more records to be processed. It processes one record at a time, rather than grabbing ten and processing those at once within the same while loop. Is something wrong with my code or query?
Thanks for the help.
The culprit is your reassigning of the data reader using reader = command.ExecuteReader();. That will now return 1 result and your next loop will be over that 1 result. Regardless for non SELECT queries use ExecuteNonQuery instead.
Other places that you can update your code to be "better" are
Use parameters whenever you have values that you want to use in your sql statements.
Always specify the type for all your parameters.
Always wrap your types instances that implement IDisposable in using blocks to ensure resources are cleaned up.
I also recommend you not share connection instances, below it seems that there might be a static connection somewhere. It would be best to not share one and create/open one when you need it and then close/dispose it.
string inProgressQuery = "SELECT TOP 10 IDType, ID, Program, Date, Body,
AcctNo, ANPACAcctID, ANPACClientID, TEAMID,
ImportDate, AnnualReview, TeamGUID,
ANPACClientLastName, ANPACClientFirstName, " +
"PolicyNumber, AccountOwnerLastName,
AccountOwnerFirstName, SCRACF, SCDateTime, NoteID
FROM NoteTable WHERE SQLMigrationFl = ?";
using(var command = new OleDbCommand(inProgressQuery, connection))
{
// I guessed on the type and length
command.Parameters.Add(new OleDbParameter("SQLMigrationFl", OleDbType.VarChar, 10)).Value = "I";
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
//clear the In Progress flag
const string UpdateQuery = "UPDATE NoteTable SET SQLMigrationFl = ? WHERE NoteTable.NoteID = ?";
using(var commandUpdate = new OleDbCommand(UpdateQuery, connection))
{
commandUpdate.Parameters.Add(new OleDbParameter("SQLMigrationFl", OleDbType.VarChar, 10)).Value = DBNull.Value;
commandUpdate.Parameters.Add(new OleDbParameter("NoteId", OleDbType.Int)).Value = reader[19];
commandUpdate.ExecuteNonQuery();
}
}
}
}
Hi I am trying to create CRUD functions in C# but am stuck on my first one which is FetchALL, as so far it says not all code path returns a value.
Heres my code so far
public SqlDataReader FetchAll(string tableName)
{
using (SqlConnection conn = new SqlConnection(_ConnectionString,))
{
string query = "SELECT * FROM " + tableName;
SqlCommand command = new SqlCommand(query, conn);
using (SqlDataReader reader = command.ExecuteReader())
conn.Open();
conn.Close();
}
}
}
}
I can give you more information, thanks
You have a return type of SqlDataReader, but you aren't returning anything anywhere in your code. At the very least you should declare your data reader and return it like this:
public SqlDataReader FetchAll(string tableName)
{
SqlDataReader reader;
using (SqlConnection conn = new SqlConnection(_ConnectionString))
{
string query = "SELECT * FROM " + tableName;
// added using block for your command (thanks for pointing that out Alex K.)
using (SqlCommand command = new SqlCommand(query, conn))
{
conn.Open(); // <-- moved this ABOVE the execute line.
reader = command.ExecuteReader(); // <-- using the reader declared above.
//conn.Close(); <-- not needed. using block handles this for you.
}
}
return reader;
}
Note, I've noted a few other problems I saw as well, which you can see by my comments.
Also, I want to point out something very important: you should always avoid string concatenation in queries as this opens you up to the risk of a SQL injection attack (as gmiley has duly pointed out). In this case, you should create an enum which contains values associated with all the possible table names, and then use a dictionary to look up the table names based on their enum values. If a user provides an invalid/unknown value, you would then thrown an argument exception.
This isn't the end of your problems, though (as Default has pointed out). You can't create the connection in a using block, which disposes and closes as soon as it exits the block, and then use the SqlDataReader that is returned from the method. If I were you, I'd return a DataSet instead of a SqlDataReader. Here's how I'd do it:
First, create your enum of possible table values:
public enum Table
{
FirstTable,
SecondTable
}
And a dictionary that maps table enum values to the table names (which you will populate in your static constructor):
private static Dictionary<Table, string> _tableNames = new Dictionary<Table, string>(); // populate this in your static constructor.
And then here is your method to fetch the data:
public static System.Data.DataSet FetchAll(Table fromTable)
{
var ret = new System.Data.DataSet();
using (var conn = new System.Data.SqlClient.SqlConnection(_connectionString))
{
string tableName = "";
if (!_tableNames.TryGetValue(fromTable, out tableName)) throw new ArgumentException(string.Format(#"The table value ""{0}"" is not known.", fromTable.ToString()));
string query = string.Format("SELECT * FROM {0}", tableName);
using (var command = new System.Data.SqlClient.SqlCommand(query, conn))
{
using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
adapter.Fill(ret);
}
}
}
return ret;
}
One final note, I'd advise you name your class-level variables with lower camel case per convention, e.g. _connectionString.
Firstly you aren't returning anything from the method. I'd add, are you sure you want to return a SqlDataReader? It is declared within a using block, so it will be closed by the time you return it anyway. I think you should re-evaluate what this function should return.
You need a return statment for the method to return a value.
I need to retrieve a value from a field in database. I have the used following code. but the value checkOrderId (which I need) shows the SQL string instead of the value from database. I don't know why it is doing so. Could somebody help me please?
string connectionString = "Data Source = xxyyzz;Initial Catalog = xyz; Integrated Security = True";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From" + tableName + "ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
//cmd.ExecuteNonQuery();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == checkOrderId)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
I am new and dont have reputation to answer my question immediately. With everybody's help, i got this one solved...Great help, thanx everybody...following is my code.
string connectionString = "Data Source = EAEDEV;Initial Catalog = GIS; Integrated Security = True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string tableName = "[GIS].[SecondaryTraffic].[PotentialBackHauls]";
string checkOrderId = "Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
string valueReturned = (string)cmd.ExecuteScalar();
OpenPop.Pop3.Pop3Client popConn = new OpenPop.Pop3.Pop3Client();
if (orderIdentity == valueReturned)
{
popConn.DeleteMessage(messageNumber);
}
connection.Close();
}
You need to execute the query and check the results, here you are just comparing a string with the query SQL.
Please see here
http://www.csharp-station.com/Tutorial/AdoDotNet/lesson03
for a tutorial.
Your expectation of the result being set into checkOrderId is incorrect. In this instance checkOrderId is just the query to execute and not the actual result.
You need to read the value back from executing the command:
using (var connection = new SqlConnection(connectionString))
using (var comm = new SqlCommand("Select TOP 1 OrderID From [GIS].[SecondaryTraffic].[PotentialBackHauls] ORDER BY InsertDate DESC", connection))
{
connection.Open();
object result = comm.ExecuteScalar(); // This is the key bit you were missing.
if (result != null)
{
// You can cast result to something useful
int orderId = (int)result;
}
} // Both comm and connection will have Dispose called on them here, no need to Close manually.
ExecuteScalar returns the value in the first cell (ie, column 1 row 1) as an object that you can cast to a better type (depending on what type it was in the result-set schema).
If you need to read multiple values, you need to look at ExecuteReader.
There are also other ways of doing this using output parameters, but that would pollute the point of the answer.
You can add space to your query
"Select TOP 1 OrderID From " + tableName + " ORDER BY InsertDate DESC";
Nota : I suggest you to use AddWithValue method with your parameter
string checkOrderId = "Select TOP 1 OrderID From #tableName ORDER BY InsertDate DESC";
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
cmd.Parameters.AddWithValue("#tableName", tableName );
Link : http://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqlparametercollection.addwithvalue.aspx
You don't actually run your command anywhere. Instead of the commented-out cmd.ExecuteNonQuery, you should look into the ExecuteScalar method, which allows you to read back a single result value from a query - which is what your query returns.
Add
int i = (Int32) cmd.ExecuteScalar();
right after
SqlCommand cmd = new SqlCommand(checkOrderId, connection);
then the variable i will contain the order id
No, this is not correct. You are comparing the variable orderId to your query string. I doubt that's what you want to do. I imagine you'd be better off calling cmd.ExecuteScalar() to retrieve the actual OrderID value. As noted by other answers, your query string is missing a space. But most importantly, it is bad practice to construct SQL queries in code. Although I can't see a security issue with this code, if you continue to use this method you will probably write code that is vulnerable to SQL injection. I recommend you learn to either use parameters or LINQ to build your queries.