Retrieving more than one value from database and store them - c#

What I'm trying to do is retrieve the FullName values where the Username corresponds to the user, which does indeed work, the problem is I don't exactly know how to store the values when there is more than one value, I tried using an array but when there is for example two values, when retrieving it, characterReader[0] will be null and characterReader[1] will have only the first retrieved value, however if there is only 1 value to be retrieve characterReader[0] will no longer be null and display the correct value.
This is my code, I'm not exactly sure this is even the right way:
SqlCommand displayCharactersCMD = new SqlCommand(String.Format("SELECT FullName FROM [Characters] WHERE Username='{0}'", username), con);
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
int counter = 0;
while (reader.Read())
{
if (counter != countCharsToVar)
{
characterReader = new string[countCharsToVar];
characterReader[counter] = reader[0].ToString();
counter++;
}
else
break;
}
}
Example when there are two values to be retrieved:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will become null.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will contain the first value.
How I intend it to work:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will display first value.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will display second value.

Instead of storing values in array, you can utilize List<>. This might help you:
SqlCommand displayCharactersCMD = new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName");
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
var characterReader = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
characterReader.Add(reader[0].ToString());
}
}

Here's a really good link from Microsoft: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/retrieving-data-using-a-datareader
Use the GetString(columnNumber) method to get the whole value from the row. That should make it easy for you.
Hope this helps.

You need to iterate SqlDataReader for each value, calling reader.Read() makes the reader to point to the next row, when it reaches the end and there is no more rows in the resultset it returns false.
When a "read" is done, the reader is moved to point to the next row so you can access all the columns in this way. reader[0] will be the first column, reader[1] for the second column and so on, in your example you only have one column fullname.
You can add all your results to a list in this way:
var values = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0]);
}
}
Note: as #steve points, parameter does not work that way, you remove the string.format call and use the name of the parameter.
new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName"), con);

Related

How to get all the values in a row of a DB relation and assign each of them to a variable in ASP.NET C#

I'm trying to find a way to have access to all the values in a row.
The following code returns one cell. If I change select id to select *, I have access to the row but how can I break it apart?
string find_user = "select id from users where userName = '" + un + "'";
using (SqlConnection con = new SqlConnection(cs))
{
using (SqlCommand cmd = new SqlCommand(find_user, con))
{
con.Open();
user_id = cmd.ExecuteScalar().ToString();
/* use to pass the info to all the pages */
Session.Add("u_id", user_id);
}
}
You cannot access additional columns using .ExecuteScalar(), per the docs:
Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
Although it is not a route that I would recommend, you can iterate through the fields by using an index on a data reader:
SqlDataReader dataReader = cmd.ExecuteReader();
// for the query's result set, this while loop will go through all the records
while (dataReader.Read())
{
// for the current record, this for loop will go through all the fields
for (int i = 0; i < dataReader.FieldCount; i++)
{
var value = dataReader[i]; // do what you need with the data here
}
}
A better approach would be to specify the field names in the SQL query instead of using SELECT *, then get the values from the data reader by the specific field names (not relying on the order of the fields in the DB).
Also, you have a SQL injection vulnerability. You should look up what this means and how to parameterize a query.

ADO SqlReader fails after read()=true: Invalid attempt to read when no data is present

I have the following piece of code (modified after some answers):
String sql = "SELECT invoice_pk FROM invoices WHERE invoice_number = " + InvoiceNumberLabel.Text;
SqlCommand cmd = new SqlCommand(sql, invoiceHeaderOnOSDconn);
SqlDataReader invoiceResult = cmd.ExecuteReader();
if (invoiceResult.HasRows)
{
if (invoiceResult.Read())
{ // As Rahul suggested (even though the post is now deleted) I added this third check and it worked
if (invoiceResult["invoice_pk"] != DBNull.Value)
{
String invoice_pk = invoiceResult["invoice_pk"].ToString();
}
}
invoiceResult.Close();
}
As far as I know, it shouldn't fail because I am double checking the result, first with "HasRows" and next with if "Read()".
Now, although the code works I am more confused than before, because with the same values it started to work.
Could somebody tell me why?
Thanks in advance.
Try invoiceResult.GetString() with column idx or column name.

SQL reader cannot read all the checkListBox checkedItems

I am working on a windows form application using c#. I have a problem with trying to match the checked data from my checkListBox to my sql data checkbox column. What I am trying to do is a binded the checkListBox to one of my column in my database table let's call it employee_detail which can fetch the data from database correctly. However, when I am trying to export the checked items from that checklistbox, I can only read the first checked item from the checklistbox. If I have 3 items and I checked all 3 items, my excel only show the 1st checked items. I have no idea why. For example, I have Amy, Peter and Jimmy in my checkListBox. When I select Amy, it will export the name Amy to my excel table. However, if I select all 3 (Amy, Peter and Jimmy), it only export Amy to my excel even though I have 3 checked. I have no idea why it doesn't work.
What I tried first time. This is a complete disaster. The HasRow in my datareader cannot fetch any column from my db even I can execute the same query in my sql console and find the column I am looking for. This loop skip whatever it is inside the while loop since HasRow = false
Here is my first attempted
foreach(var items in checkListBox1.CheckedItems){
string query = "select * from my_table WHERE employeeName = '"+items+"'"
SqlCommand myCommand = new SqlCommand(query, myConn);
SqlDataReader dr = myCommand.ExecuteReader();
while(dr.Read()){
//read the column
}
}
My second attempt is using the parameters, this seems to work, but the problems (what I suggested above) is my excel files only showed the first checked items (I believe it only loop through the while loop once), when my db table has more then one record
Here is my second attempted
foreach (var item in employeeCheckListBox.CheckedItems)
{
if (items.Length == 0)
{
items = item.ToString();
}
else
{
items = items + "," + item;
}
string query = #"select * from [employeeId_detail] as td LEFT JOIN[order_detail] as cd ON td.employeeId = cd.employeeId Where employeeName in (#name)";
myCommand = new SqlCommand(query, myConn);
myCommand.Parameters.Add("#name", SqlDbType.NVarChar);
myCommand.Parameters["#name"].Value = items;
SqlDataReader dr = myCommand.ExecuteReader();
while (dr.Read())
{
i++;
{
string f_Name = dr.GetString(0);
string l_Name = dr.GetString(1);
string full_Name = dr.GetString(2);
string e_email = dr.GetString(3);
xlEmployeeDetail.Cells[i, 1] = f_Name;
xlEmployeeDetail.Cells[i, 2] = l_Name;
xlEmployeeDetail.Cells[i, 3] = full_Name;
xlEmployeeDetail.Cells[i, 4] = e_email;
}
}
dr.Close();
}
Reference to our chat: Problem is not in the code block that you wrote. The problem lies within the characters that you are using for the fetching the content out of DB.
As we tested, this block of code works fine with the English characters but fails to Chinese characters which is all together a separate problem.
However if you still would go for the Chinese character then probably you would need to do settings at the DB level, and your same code will work fine.
Parameterizing is definitely the better way to go, like in your second example.
The problem is, I'm fairly certain your query ends up looking like this, where you're passing it a single name with a couple commas in it, not a list of separate names:
select *
from [employeeId_detail] as td
LEFT JOIN[order_detail] as cd ON td.employeeId = cd.employeeId
Where employeeName in ('joe, bob, sue')
Instead, here's something a bit more dynamic, creating a parameter for each checked item.
string parameterList = "";
int parameterCounter = 0;
// Add a parameter placeholder for each "checked" item
for (var i=0; i<checkListBox1.CheckedItems.Count; i++)
parameterList += (i==0) ? "#p" + i : ", #p" + i;
string query = #"select *
from [employeeId_detail] as td
LEFT JOIN[order_detail] as cd ON td.employeeId = cd.employeeId
Where employeeName in (" + parameterList + ")";
myCommand = new SqlCommand(query, myConn);
// Now give each parameter a value from the collection of checked items
for (var i = 0; i < checkListBox1.CheckedItems.Count; i++)
myCommand.Parameters.AddWithValue("#p" + i, checkListBox1.CheckedItems[i].ToString());
SqlDataReader dr = myCommand.ExecuteReader();

SqlDataReader - correct syntax, must I hardcode column number?

I have a database named testDB, which contains table Versions, which contains a column [Release Date] with datetime format.
Now, I want to read it in my C# Windows Service:
protected void SqlConnect()
{
SqlCommand comSql;
DateTime relDate;
SqlDataReader myReader = null;
using (SqlConnection myConnection = new SqlConnection(_server +
_username +
_password +
"Trusted_Connection=yes;" +
"database=testDB; " +
"connection timeout=30"))
{
try
{
myConnection.Open();
comSql = new SqlCommand("select [Release Date] from dbo.Version",
myConnection);
myReader = comSql.ExecuteReader();
while (myReader.Read())
{
//Here's my problem, explained below
}
}
catch
{
}
finally
{
if (myReader != null) myReader.Close();
}
}
}
Now, I want to assign the value stored in that column to relDate variable. However
relDate = myReader.GetDateTime();
requires GetDateTime to have column number passed there (if I understand this right). But I already selected column in my comSql. Is this the correct way to deal with this problem, ie. just putting the column number in the code?
EDIT: Ok judging by the answers I might word this question wrong or something.
I know that I must pass the column index to GetDateTime(). I ask if there's a way to do that without hardcoding it like GetDateTime(0).
You can use GetOrdinal method on the data reader to get ordinal of the column from its string name. In that way, you won't have to hardcode the column index.
GetOrdinal is also useful when you're reading data from the data reader in a loop. You can initialize the index variable before the loop starts and then use it in every iteration of the loop.

SqlDataReader Reader.Read() shows Enumeration yielded no results

I am Trying to generate random Ids from a given table. I can see the random number generated in debug but when I reach to reader.Read() line it shows Enumeration yielded no results.
I couldn't quite get what I am missing.
private static void GetRandomId(int maxValue)
{
string connectionString =
"Data Source=local;Initial Catalog=Test;user id=Test;password=Test123;";
string queryString = #"SELECT TOP 1 Id from Pointer WHERE Id > (RAND() * #max);";
using (var connection = new SqlConnection(connectionString))
{
var command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#max", maxValue);
connection.Open();
using (var reader = command.ExecuteReader()) <-- // Here I can see the randon value generated
{
while (reader.Read())
{
//Here reader shows : Enumeration yielded no results
Console.WriteLine("Value", reader[1]);
reader.Close();
}
}
}
}
Since you are basically searching for a random Id of an existing record, I believe this may cover what you are trying to do:
Random record from a database table (T-SQL)
SELECT TOP 1 Id FROM Pointer ORDER BY NEWID()
Use SqlCommand.ExecuteScalar Method instead
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar%28v=vs.110%29.aspx
var dbRandomId = command.ExecuteScalar();
var randomId = Convert.IsDbNull(dbRandomId) ? (int?)null : (int)dbRandomId;
// you now also know if an id was returned with randomId.HasValue
https://msdn.microsoft.com/en-us/library/system.convert.isdbnull%28v=vs.110%29.aspx
Issues with your example:
Issue 1: Couldn't you have #max be computed with a SELECT #max = MAX(Id) FROM Pointer? No need to pass it in a parameter. Or am I missing the point? Is that a deliberate limit?
Issue 2: Shouldn't it be reader[0] or reader["Id"]? I believe columns are zero based and your selected column's name is "Id".
Issue 3: Be careful not to enumerate somehow the reader via the Debugger because you'll actually consume (some of?) the results right there (I'm guessing you are doing this by your comment "// Here I can _see_ the random value generated") and by the time the reader.Read() is encountered there will be no results left since the reader has already been enumerated and it won't "rewind".
https://msdn.microsoft.com/en-us/library/aa326283%28v=vs.71%29.aspx
DataReader cursor rewind
Issue 4: Why do you close the reader manually when you've already ensured the closing & disposal with using? You also already know it's going to be one record returned (the most) with the TOP 1.
If you check the results of the sqlDataReader in the debugger, the results are then gone, and wont be found by the Read() event

Categories