I have a database that stores invoice information. Each invoice can have up to 5 jobs relation, each job has a unique id number.
I've performed a select statement selecting all jobs relevant to a single invoice.
I have tried many ways to read the selected job id and store them in a jobArray. I would prefer to have it selecting using a for loop but most of the ways I've tried use textBoxes (which I replaced with my array)
This is my most recent code;
SqlCeCommand cmdCountJobs = new SqlCeCommand("SELECT COUNT(Job_ID)AS INVCOUNT FROM Invoice WHERE Invoice_Number = " + maxInvoice + " ", cn);
cmdCountJobs.Connection = cn;
reader = cmdCountJobs.ExecuteReader();
while (reader.Read())
{
countValue = Convert.ToInt32(reader["INVCOUNT"].ToString());
}
SqlCeCommand cmdJobSearch = new SqlCeCommand("SELECT Job_ID as ID FROM Invoice WHERE Invoice_Number = " + maxInvoice + " ", cn);
cmdJobSearch.Connection = cn;
reader = cmdJobSearch.ExecuteReader();
SqlCeDataAdapter da = new SqlCeDataAdapter(cmdJobSearch);
jobArray[0] = (reader.Read()) ? reader["ID"].ToString() : "";
jobArray[1] = (reader.Read()) ? reader["ID"].ToString() : "";
jobArray[2] = (reader.Read()) ? reader["ID"].ToString() : "";
jobArray[3] = (reader.Read()) ? reader["ID"].ToString() : "";
jobArray[4] = (reader.Read()) ? reader["ID"].ToString() : "";
}
Could you help me with this?
Why use an array? You could use a List(Of Int) to store the ID numbers using a normal loop.
And given the nature of lists you don't need to know before hand the number of jobs to set your array size, so you could have an Invoice with only 4 jobs or one with 6, but the logic of your code will not need to check for this.
List<int> jobs = new List<int>();
SqlCeCommand cmdJobSearch = new SqlCeCommand("SELECT Job_ID as ID FROM Invoice " +
"WHERE Invoice_Number = #ivc", cn);
cmdJobSearch.Connection = cn;
cmdJobSearch.Parameters.AddWithValue("#ivc", maxInvoice);
reader = cmdJobSearch.ExecuteReader();
while(reader.Read())
jobs.Add(Convert.ToInt32(reader["ID"]));
Also note that I have changed your query to avoid string concatenation. Probably this is not the case but it is a good practice to use parametrized queries to avoid Sql Injection
Of course, if you have the need to use an array somewhere in the remainder of your code, you can easily reference the list like an array
TextBox1.Text = jobs[0].ToString();
or convert the list back to an array with
int[] ids = jobs.ToArray();
Related
So I am trying to use two different inputs from a user to get two different values then multiply them together to get an answer.
//code to get value
SqlCommand cmd = new SqlCommand("select Charges, Students from Subs where Subject_name='" + Subject + "'and Level='" + Level + "'", con);
//code to read and times the values
var reader = cmd.ExecuteReader();
int Price = Convert.ToInt32(reader["Charges"]);
int NumS = Convert.ToInt32(reader["Subject_name"]);
int final = (Price*NumS) / 100;
status = final + "$";
You should try something like this:
// Define **parametrized** query
string query = "SELECT Charges, Students FROM dbo.Subs WHERE Subject_name = #SubjectName AND Level = #Level;";
using (SqlCommand cmd = new SqlCommand(query, con))
{
// define the parameters and set value
// I'm just *guessing* what datatype and what length these parameters are - please adapt as needed !
cmd.Parameters.Add("#SubjectName", SqlDbType.VarChar, 50).Value = Subject;
cmd.Parameters.Add("#Level", SqlDbType.Int).Value = Level;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
int Price = reader.GetInt32(0); // index = 0 is "Charges" of type INT
// you are **NOT** selecting "Subject_Name" in your query - you therefore **CANNOT** read it from the SqlDataReader
// int NumS = Convert.ToInt32(reader["Subject_name"]);
int NumS = 1.0;
int final = (Price * NumS) / 100;
status = final + "$";
}
}
Points to ponder:
You should also put your SqlConnection con into a proper using (..) { ... } block to ensure disposal
You need to check the parameters - since you hadn't specified anything in your question, and also not posted any information about them, I can only guess
Be aware - the SqlDataReader might (and in a great many cases will) return multiple rows - which you need to iterate over
If you want to read out a column from the database table - it must be in the SELECT list of columns! You're trying to read out a column you're not selecting - that won't work, of course. ...
Since yesterday I am trying to get this value (see image), I have tried to use "mysqlreader, executescalar and more", but I cannot get the number of lines.
What I want to do is this:
If the result is 0 it does nothing, if equal to 1 it must show an image, if greater than 1 it must show another image
ex code 1
private void patient()
{
if (OpenEventMissionData.Rows.Count != 0)
{
foreach (DataGridViewRow row in OpenEventMissionData.Rows)
{
string idevent = row.Cells[1].Value.ToString();
string sql = "SELECT COUNT(*) FROM patient INNER JOIN event WHERE patient.ID_EVENT = " + "'" + idevent + "'" + "AND evento.EVENT_OPEN = 1;";
MySqlConnection connection = new MySqlConnection();
connection.ConnectionString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
MySqlCommand cmd = new MySqlCommand(sql, connection);
connection.Open();
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
DataGridViewButtonColumn patient = new DataGridViewButtonColumn();
OpenEventMissionData.Columns.Add(new PatientColumn());
}
}
}
}
I tried adding the code that told me #oldDog, but the result is always 6
ex code 3
NEW EDIT:
In fact 6 lines appear.
phpmyadmin
Your problem here is you are using HasRows. Since you are doing SELECT COUNT(*) you will always have one row which will contain the count, even if the count is zero. Instead you could use:
if (Convert.ToInt32(reader[0]) > 0)
else if (listBox1.SelectedIndex == 1)
{
String sql2 = "SELECT FirstName, LastName FROM Players WHERE Team = 'Milwaukee Bucks'" +
"AND Number < 24";
// command statement
command = new SqlCommand(sql2, cnn);
SqlDataReader reader = command.ExecuteReader();
// Get table values
if (reader.Read())
{
textBox1.Text = reader.GetString(0).ToString() + " " + reader.GetString(1).ToString();
}
cnn.Close();
command.Dispose();
}
Above is a section of my code. I have a list box with options for the user to choose, and based on which item is selected, a display button will run a query and return the results to a textbox.
However, when I run the code I am only getting one result back. The query returns players on the Bucks who have a number less than 24. There should be multiple of them but I am only getting one in my C# application.
You need to use a while loop to read all the lines instead of reading a single line (via Read()).
Microsoft Documentation has an example of how to use the while loop.
StringBuilder sb = new StringBuilder()
while (reader.Read())
{
sb.AppendLine(reader.GetString(0).ToString() + " " + reader.GetString(1).ToString());
}
textBox1.Text = sb.ToString();
I have this code which returns the correct data from one table. But I have related data in other tables using INNER JOIN. So my question is how to code to return this in the result?
IList<Schedule> GetCurrentValues()
{
var result = new List<Schedule>();
using (var sqlConnection = new SqlConnection(_configuration["DefaultConnection"]))
{
sqlConnection.Open();
using (var command = sqlConnection.CreateCommand())
{
command.CommandText = "SELECT Schedules.AppointmentHeading, Schedules.AppointmentDateStart, Schedules.AppointmentDateEnd, Bookers.Email, Rooms.Id AS Expr3, Rooms.Name " +
"FROM Schedules " +
"INNER JOIN Rooms ON Schedules.RoomId = Rooms.Id " +
"INNER JOIN Bookers ON Schedules.BookerId = Bookers.Id";
command.CommandType = CommandType.Text;
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
// How should I code so I also get Bookers.Email and Room.Name?
}
}
}
}
}
return result;
}
Since you need a mixed data from different tables, it is recommended to either create new Model which will consist of the properties you actually care like
AppointmentHeading, AppointmentDateStart, AppointmentDateEnd, BookingEmail, RoomName
or just add BookingEmail & RoomName to your existing Schedule Model.
using (var sqlConnection = new SqlConnection(_configuration["DefaultConnection"]))
{
sqlConnection.Open();
using (var command = sqlConnection.CreateCommand())
{
command.CommandText = "SELECT Schedules.AppointmentHeading, Schedules.AppointmentDateStart, Schedules.AppointmentDateEnd, Bookers.Email as BookingEmail, Rooms.Id AS Expr3, Rooms.Name as RoomName" +
"FROM Schedules " +
"INNER JOIN Rooms ON Schedules.RoomId = Rooms.Id " +
"INNER JOIN Bookers ON Schedules.BookerId = Bookers.Id";
command.CommandType = CommandType.Text;
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
result.AppointmentHeading = Convert.ToString(reader["AppointmentHeading"]);
result.AppointmentStart = Convert.ToDateTime(reader["AppointmentDateStart"]);
result.AppointmentEnd = Convert.ToDateTime(reader["AppointmentDateEnd"]);
result.BookingEmail = COnvert.ToString(reader["BookingEmail"]);
result.RoomName = Convert.ToString(reader["RoomName"]);
}
}
}
}
}
Just reference the column names in the SqlDataReader - it returns a "flat" set of all the columns selected, and you can access these via the column name (or the column alias AS .... if one is given). Then store those values as needed, e.g. in a separate class or whatever works for you:
....
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
// read the individual values and store them as needed
string appointmentHeading = reader["AppointmentHeading"];
DateTime appointmentStart = Convert.ToDateTime(reader["AppointmentDateStart"]);
DateTime appointmentEnd = Convert.ToDateTime(reader["AppointmentDateEnd"]);
string email = reader["Email"];
string roomId = reader["Expr3"];
string roomName = reader["Name"];
// possibly create a custom class here to hold these values
// and store the multiple possible rows returned into a list of those classes
// - or do whatever you need to do with these values here.....
}
}
Create a new class containing all the columns of select statement.
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());
............
}