what's wrong pls?
I can get number of records but can't get id value of each record
I have this function to count and get id values:
I think the issue is in the function
form1
public List<int> countInTable(Double codebar)
{
cmd.Connection = cn; // sqlconn
cn.Open();
List<int> id = new List<int>();
String countString = "SELECT COUNT (*) FROM medicaments WHERE code_bare = #codebar ";
var myCommand = new SqlCommand(countString, cn);
myCommand.Parameters.AddWithValue("#codebar", codebar);
int count = Convert.ToInt32(myCommand.ExecuteScalar());
id.Add(count);
using (rd = myCommand.ExecuteReader())
{
// loop over all rows returned by SqlDataReader
while (rd.Read())
{
// grab the column no. 0 (id" from
// SQL select statement) as a string then int, and store it into list of id
t0 = rd[0].ToString();
id.Add(int.Parse(t0));
}
}
rd.Close();
cn.Close();
return id;
}
Then i call the first function in another form to get data of each record
form2
private void laodProduct(Double codebar)
{
this.listView2.Items.Clear();
List<int> total = manipBaseDonnees.countInTable(double.Parse(textBox2.Text));
foreach (int t in total)
{
listBox1.Items.Add(t);
List<string> donnees = manipBaseDonnees.getFromTableID(t);
var item1 = new ListViewItem(new[] { donnees[1], donnees[2], donnees[6], donnees[7], donnees[8], donnees[4], donnees[0] }, -1, Color.Empty, Color.Yellow, null);
this.listView2.Items.AddRange(new ListViewItem[] { item1 });
}
}
Your query is a count query, you cannot use the same query to get each entry. You need to use a second query for that:
string query = "SELECT * FROM medicaments WHERE code_bare = #codebar";
If you only want the ID field, then only include that in your query:
string query = "SELECT ID FROM medicaments WHERE code_bare = #codebar";
In addition, if you are just going to iterate over all the results anyway, you might as well just drop he count query and count the results of ExecuteReader as you loop over them.
The problem is not with your function but with the way you select data, you use aggregate function COUNT(*) and this returns only row count if you add MAX(ID) this will do same think as if you would've grouped your data by ID what is wrong with is is that in that case you will get two columns one will be ID value and the second one would've been COUNT but it would be the same for all the ID's
String countString = "SELECT MAX(ID), COUNT (*) FROM medicaments WHERE code_bare = #codebar ";
oh yes Thanks, I copied the string from my first function without giving attention
string query = "SELECT * FROM medicaments WHERE code_bare = #codebar";
Related
I am making changes in an old C# WinForm application.
In the code below, when the DoWork() function is invoked. It calls the two functions PerformOperation1 and PerformOperation2. Both functions have a very similar body. The only difference is that they both update different fields of the same database table.
Finally, when they both have performed their job, we fetch the records using an OracleDataAdapter.
The count of the rows returned is 0 in the code. However, if I execute the query on the database straight away, it returns some rows. This means somehow the records updated by the PerformOperation2 are not pushed to the database at the time when we call the Fill on the DataAapter.
public void DoWork()
{
PerformOperation1();
PerformOperation2();
var sql = "select * from results where result_id = 1 and is_valid = 'Y'";
var table = new DataTable();
var data = new OracleDataAdapter(new OracleCommand(sql, base.Connection));
data.Fill(table);
var count = data.Rows.Count; //It returns 0 But when execute the same query on database, it returns rows.
}
public void PerformOperation1()
{
string sql = "select seq_1, product, count_1, count_2 from results where result_id = 1";
string updateSQL = "update results set count_1 = :count_1, count_2 = :count_2 WHERE seq_1 = :seq_1";
var selectCmd = new OracleCommand(sql, base.Connection);
selectCmd.CommandType = CommandType.Text;
var adapter = new OracleDataAdapter(lCmd);
adapter.UpdateCommand = new OracleCommand(updateSQL, base.Connection);
adapter.UpdateCommand.CommandType = CommandType.Text;
AddCommandParameter(adapter.UpdateCommand, ":count_1", DbType.Double, 11, "count_1");
AddCommandParameter(adapter.UpdateCommand, ":count_2", DbType.Double, 11, "count_2");
var data = new DataSet();
adapter.Fill(data);
foreach (var row in data.Tables[0].Rows)
{
row["count_1"] = GetCount1(row["seq1"]); //Returns Count1
row["count_2"] = GetCount2(row["seq1"]); //Returns Count2
//Forces an immediate garbage collection of all generations
GC.Collect();
GC.WaitForPendingFinalizers();
}
adapter.Update(data);
data.AcceptChanges();
}
public void PerformOperation2()
{
string sql = "select seq_1, product, is_valid from results where result_id = 1";
string updateSQL = "update results set is_valid = :is_valid WHERE seq_1 = :seq_1";
//Does exactly the samething like PerformOperation1 function above.
//100% same code.
//Only difference is that it updates different column named is_valid (with value 'Y' or 'N')
}
public void AddCommandParameter(DbCommand aoCommand, string asParamName, DbType aoDataType, int aiSize, string asColName)
{
if (aoCommand is OracleCommand)
{
OracleCommand loCommand = (OracleCommand)aoCommand;
OracleType loOraDataType = ConvertToOracleType(aoDataType);
loCommand.Parameters.Add(asParamName, loOraDataType, aiSize, asColName);
}
}
Any idea why this is happening, please?
I figured it out. It was not a coding issue. It was some underlying database view problem.
Update: as the original question was essentially answered, I've marked this as complete.
I have a C# project in which I'd like to query a database. The SQL query will SELECT from a table, and in the WHERE clause I want to filter the results from a pre-defined list of values specified in C#.
List<string> productNames = new List<string >() { "A", "B", "C" };
foreach (name in productNames)
{
string query = #"
SELECT *
FROM products
WHERE name IN (#name);";
// Execute query
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("name", name);
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
}
However I'm getting an error:
There is already an open DataReader associated with this Connection
which must be closed first
Is it not possible then to use a for loop to add parameters this way to a SELECT statement?
You need to dispose your object to not get the exception. However you don't need to iterate over values and run a query for every value in the list. Try the following code. It makes a parameter for every value and adds it to command to use in "IN (...)" clause.
Also "using" keywords handles disposing objects.
List<string> productsIds = new List<string>() { "23", "46", "76", "88" };
string query = #"
SELECT *
FROM products
WHERE id IN ({0});";
// Execute query
using (MySqlCommand cmd = new MySqlCommand(query, dbConn))
{
int index = 0;
string sqlWhere = string.Empty;
foreach (string id in productsIds)
{
string parameterName = "#productId" + index++;
sqlWhere += string.IsNullOrWhiteSpace(sqlWhere) ? parameterName : ", " + parameterName;
cmd.Parameters.AddWithValue(parameterName, id);
}
query = string.Format(query, sqlWhere);
cmd.CommandText = query;
using (MySqlDataReader row = cmd.ExecuteReader())
{
while (row.Read())
{
// Process result
// ...
}
}
}
You are doing few things wrong. Let me point out them:
Everything is fine in the first iteration of the loop, when you are in second iteration the First Reader associated with the command remains opened and that result in current error.
You are using Where IN(..) you you can specify the values within IN as comma separated so there is no need to iterate through parameters.
You can use String.Join method to construct this values with a comma separator.
Now take a look into the following code:
List<int> productsIds = new List<int>() { 23, 46, 76, 88 };
string idInParameter = String.Join(",", productsIds);
// Create id as comma separated string
string query = "SELECT * FROM products WHERE id IN (#productId);";
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("#productId", idInParameter);
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
Please note if the id field in the table is not integers then you have to modify the construction of idInParameter as like the following:
idInParameter = String.Join(",", productsIds.Select(x => "'" + x.ToString() + "'").ToArray());
Pass the comma separated productIds string instead of looping. Read more about IN here.
string productIdsCommaSeparated = string.Join(",", productsIds.Select(n => n.ToString()).ToArray())
string query = #"
SELECT *
FROM products
WHERE id IN (#productId);";
// Execute query
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("productId", productIdsCommaSeparated );
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
The error you are getting is because you do not close the MySqlDataReader. You must close it to get rid of error before you call ExecuteReader in next iteration but this is not proper way in this case.
From what I tried and tested seems best solution (especially for text column types) is to create a list of individual parameters and add it as a range the to the query and parameters.
e.g:
List<MySqlParameter> listParams = new List<MySqlParameter>();
for (int i = 0; i < listOfValues.Length; i++)
{
listParams.Add(new MySqlParameter(string.Format("#values{0}", i),
MySqlDbType.VarChar) { Value = listOfValues[i] });
}
string sqlCommand = string.Format("SELECT data FROM table WHERE column IN ({0})",
string.Join(",", listParams.Select(x => x.ParameterName)));
......
using (MySqlCommand command = new MySqlCommand(sqlCommand, connection)
{
............
command.Parameters.AddRange(listParams.ToArray());
............
}
My problem is that:
I want to Select one row from the database, The data should be arrange in expiry (the ones that are not yet expired and I don't want to limit it). The items that passed the current date must be left alone. And with all the same ITEMID lets say I00001.
Then after selecting I want to Update the first row of the database. if the quantity reaches 0 then it will go the next row to update and so on.
Here is my example
Here is the current database screenshot.
I want select the itemid where = I00001 and deduct 50.
Then it should look like this
Then I want to arrange based on the expiry as I mentioned above.
Select the first row.
Deduct the 50 from the quantity. (as I also mentioned above).
Here is my code:
for (int i = 0; i < dataGridView.Rows.Count; i++)
{
cmd = new MySqlCommand(#"SELECT * FROM inventory2 WHERE itemid = #itemid ORDER BY expiry ", sqlconnection);
cmd = new MySqlCommand(#"UPDATE inventory2 SET quantity = #quantity WHERE itemid = #itemid ORDER BY expiry)", sqlconnection);
sqlconnection.Open();
cmd.ExecuteNonQuery();
sqlconnection.Close();
}
I'm open for another suggestion in doing this. I hope you understand my problem. Thank you very much. I'm sorry I cannot send another screenshot.
Try this,
void UpdateQuantity() {
// your connection string
MySqlDataAdapter adp = new MySqlDataAdapter("Select * from table where ItemID = " + 13 + " Order BY expiry", cnn); // I have test db and I used it
DataTable dt = new DataTable();
adp.Fill(dt);
int deductNum = 50;
foreach (DataRow item in dt.Rows)
{
int value = (int)item["quantity"];
if (value >= deductNum) // if had enough stock we don't need to pass the next line
{
int result = value - deductNum;
item["quantity"] = result.ToString();
break; // so need to exit from loop
}
else
{
deductNum -= value; // else we deduct value count from deduction
item["quantity"] = 0; // quantity finished so it will be 0
}
}
MySqlCommandBuilder cmb = new MySqlCommandBuilder(adp);
adp.UpdateCommand = cmb.GetUpdateCommand();
adp.Update(dt);
dataGridView1.DataSource = dt; //to show the result
}
(You can calculate :))
Hope helps,
im having a problem in reading data from two different column in same database table.
(Sorry for my bad english.)
String status = "1";
SqlConnection conn = new SqlConnection("Server=localhost;Integrated Security=true;database=WebsiteDatabase");
conn.Open();
SqlCommand cmdname = conn.CreateCommand();
cmdname.CommandText = "select product, quantity from tlbOrder where status = '1'";
//get product name and quantity
cmdname.Parameters.Add("#status", status);
SqlDataReader dr = cmdname.ExecuteReader();
StringBuilder sb = new StringBuilder();
while (dr.Read())
{
sb.AppendFormat("{0}, ", dr[0].ToString());
}
label1 = ""+sb.ToString();
However, only "product" details are return.
Expected results: label with string of Product name + quantity (e.g. Laptop 1, Keyboard 3, Speaker 5) and so on.
Well, there is no problem to add another parameter to AppendFormat
while (dremail.Read())
{
sb.AppendFormat("{0}, {1}", dr[0].ToString(), dr[1].ToString());
}
However, your code will try to insert in the same label a potentially long list of products.
Perhaps a better approach should be to use a List or a GridView
I am going to have multiple processes running at the same time so what I tried to do here is fetch 1000 rows and then update the rows i selected.. below are my Select and Update functions notice i call the update function right after closing the connection in the select function
public List<string> Select()
{
string set;
string query = "SELECT * FROM master WHERE attempted='0' LIMIT 1000";
List<string> list = new List<string>();
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (list.Count() < 1000)
{
dataReader.Read();
string email = dataReader["email"].ToString();
var m = dataReader["attempted"];
if (m.ToString() == "0")
{
list.Add(email);
}
}
dataReader.Close();
this.CloseConnection();
Update();
return list;
}
else
{
return list;
}
}
public void Update()
{
if (this.OpenConnection() == true)
{
string query = "UPDATE master SET attempted='1' WHERE ( SELECT * FROM master WHERE attempted='0' LIMIT 1000 )";
MySqlCommand cmd = new MySqlCommand(query, connection);
cmd.CommandText = query;
cmd.ExecuteNonQuery();
this.CloseConnection();
}
}
the exception i am getting it operand must contain 1 column(s)..
What am I doing wrong?
Why can't you just create a separate column, or even a table? Then write a basic Query at the SQL level or a Procedure to modify the value? Then the other applications can just test the value of the column or table.
Example:
UPDATE [dbo].[Customer]
SET [GotEmail] = 1
WHERE (
SELECT [Email]
FROM [dbo].[Customer]
);
Or something basic like that? Another example would be:
UPDATE accounts
SET (contact_last_name, contact_first_name) =
(SELECT last_name, first_name FROM salesmen
WHERE salesmen.id = accounts.sales_id);
Does a simple query like so not solve your issue?
If my response is not clear... I'll try and clarify my thought process.