I get an SQL response and record it into list of lists, representing table of results. After that I need to for example distinct values in the first "column" (first list in my list of lists). How to tie all other lists to the first one so all "rows" are stay consistent and somehow connected by index number?
Number of columns (lists) is variable.
Here is code I use to get data from SQL response:
List<List<string>> response = new List<List<string>>();
int colNum = 0;
using (OracleCommand comm = new OracleCommand(query, con))
{
using (OracleDataReader rdr = comm.ExecuteReader()) // execute the oracle sql and start reading it
{
while (rdr.Read())
{
if (response.Count == 0)
{
while (rdr.GetOracleValue(colNum) != null)
{
response.Add(new List<string>());
colNum++;
}
}
for (int c = 0; c < colNum; c++)
{
if (rdr.GetOracleValue(c).ToString() == "Oracle.DataAccess.Types.OracleClob")
{
response[c].AddRange(report.getPropertiesByName(rdr.GetOracleValue(c), "Value", false, false).Select(p => p.ToString()));
}
else
{
response[c].Add(rdr.GetOracleValue(c).ToString());
}
}
}
rdr.Close();
}
}
return response;
Take a look at the OracleDataAdapter. I'm not quite sure if this syntax is correct, but it should get you started.
var response = new DataSet();
using (OracleCommand command = new OracleCommand(query, con))
{
var dataAdapter = new OracleDataAdapter(command);
dataAdapter.Fill(response);
}
return response;
Related
I have created a method that will get data from a SQL table and store the columns of data each in their own array. Right now, when working through the debugger, what I notice is that when I am assigning values to these arrays, they are null values.
I did check to see if my query returns values in SSMS and it indeed does. So null values should not be expected.
Here is the code to the method:
public static CommentsPageData getComments(string wcNum)
{
string[] prodTimeArray = new string[24];
string[] crewsArray = new string[24];
string[] commentsArray = new string[24];
string[] redTimeArray = new string[24];
string[] greenTimeArray = new string[24];
string commandSql = "SELECT TOP 24 Production_Time, Crew, Red_Time, Green_Time, Comment FROM ************ WHERE Work_Center = #wc ORDER BY Production_Time DESC";
SqlConnection con = new SqlConnection("Data Source=*******;Initial Catalog=********;Integrated Security=True");
con.Open();
SqlCommand cmd = new SqlCommand(commandSql, con);
cmd.Parameters.AddWithValue("wc", wcNum);
CommentsPageData commPageData = new CommentsPageData();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
prodTimeArray.Append(reader["Production_Time"].ToString());
crewsArray.Append(reader["Crew"].ToString());
redTimeArray.Append(reader["Red_Time"].ToString());
greenTimeArray.Append(reader["Green_Time"].ToString());
commentsArray.Append(reader["Comment"].ToString());
}
}
else
{
Console.WriteLine("No rows found");
}
reader.Close();
}
commPageData.ProdTimes = prodTimeArray;
commPageData.Crews = crewsArray;
commPageData.GreenTime = greenTimeArray;
commPageData.RedTime = redTimeArray;
commPageData.Comments = commentsArray;
con.Close();
return commPageData;
}
Long story short, I have created a Class (CommentsPageData) which has an array for each column I'm returning 24 values from. However... The problem is in the while(reader.Read()){} section of the method. I can see it assigning values, but it is just assigning null values.
How can I actually get the values and assign them to my array correctly?
Its just like Jeroen Mostert said, Arrays in C# do not change in size after they are declared. You have declared your arrays inside the class which means the size you have initialized your arrays with is 0 which means no matter how many times you try to append elements to them, the arrays will be null. Use System.Collections.Generic List<Type> to hold your data as it can be updated to hold more elements.
public static CommentsPageData getComments(string wcNum)
{
List<string> prodTimeArray = new List<string>();
List<string> crewsArray = new List<string>();
List<string> commentsArray = new List<string>();
List<string> redTimeArray = new List<string>();
List<string> greenTimeArray = new List<string>();
string commandSql = "SELECT TOP 24 Production_Time, Crew, Red_Time, Green_Time, Comment FROM ************ WHERE Work_Center = #wc ORDER BY Production_Time DESC";
SqlConnection con = new SqlConnection("Data Source=*******;Initial Catalog=********;Integrated Security=True");
con.Open();
SqlCommand cmd = new SqlCommand(commandSql, con);
cmd.Parameters.AddWithValue("wc", wcNum);
CommentsPageData commPageData = new CommentsPageData();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
prodTimeArray.Add(reader["Production_Time"].ToString());
crewsArray.Add(reader["Crew"].ToString());
redTimeArray.Add(reader["Red_Time"].ToString());
greenTimeArray.Add(reader["Green_Time"].ToString());
commentsArray.Add(reader["Comment"].ToString());
}
}
else
{
Console.WriteLine("No rows found");
}
reader.Close();
}
commPageData.ProdTimes = prodTimeArray.ToArray();
commPageData.Crews = crewsArray.ToArray();
commPageData.GreenTime = greenTimeArray.ToArray();
commPageData.RedTime = redTimeArray.ToArray();
commPageData.Comments = commentsArray.ToArray();
con.Close();
return commPageData;
}
I would use this code
reader = cmd.ExecuteReader()
var dt=new DataTable;
dt.Load(reader);
Dictionary<string, string[]> dict = new();
for (var i = 0; i < dt.Rows.Count; i++)
{
for (var j = 0; j < dt.Rows[i].ItemArray.Length; j++)
{
if (!dict.ContainsKey(dt.Columns[j].ColumnName))
dict.Add(dt.Columns[j].ColumnName, new string[dt.Rows.Count]);
dict[dt.Columns[j].ColumnName][i] = dt.Rows[i].ItemArray[j].ToString();
}
}
and just use the dictionary
but if you want a name for each array
string[] prodTimeArray;
string[] crewsArray;
string[] commentsArray;
....
prodTimeArray = dict["Production_Time"];
crewsArray = dict["Crew"];
commentsArray = dict["Comment"];
....
If you really need to have this end result, I'd recommend just making an object representing a row in the table, use Dapper to return the rows into an IEnumerable of the objects, then to a LINQ select for each column into an array
For Example:
var results = await con.QueryAsync<MyRowObject>(commandSql, new {"wc"}, commandType: Text);
var productionTimeArray = results.Select(x => x.ProductionTime).ToArray();
After browsing a multitude topics on the phenomenon of SqlDataReader.HasRows which always returns true even with empty result (and especially when it is about an SQL query with an aggregate), I dry completely on my code
However my example is very simple and HasRows returns True, FieldCount returns 1 even when there is no phpMyAdmin side line.
query = "SELECT FK_BarId FROM tlink_bar_beer WHERE FK_BeerId = " + sqlDataReader.GetInt32(0);
MySqlConnection sqlConnexionList = new MySqlConnection("server=localhost;database=beerchecking;uid=root;password=;");
MySqlCommand commandList = new MySqlCommand(query, sqlConnexionList);
sqlConnexionList.Open();
int[] BarsIds;
using (MySqlDataReader sqlDataReaderList = commandList.ExecuteReader())
{
if (sqlDataReaderList.HasRows)
{
try
{
BarsIds = new int[sqlDataReaderList.FieldCount];
int counter = 0;
if (sqlDataReaderList.Read())
{
while (sqlDataReaderList.Read())
{
int id = sqlDataReaderList.GetInt32(counter);
BarsIds[counter] = id;
counter++;
}
}
}
finally
{
sqlDataReaderList.Close();
}
}
else
{
BarsIds = new int[0];
}
}
sqlConnexionList.Close();
Do you know how to get HasRows false when there is no rows like in phpMyAdmin result?
Thanks for reading.
I prefer to use an auxiliar DataTabe instead DataReader, something like this:
DataTable dt = new DataTable();
dt.Load(commandList.ExecuteReader());
if(dt.Rows.Count > 0){
//rows exists
}else{
//no rows
}
How can I generate an array of string that will contain all the column info.
this query will return a single row with multiple columns
var rowLines = new List<string>();
try
{
using (SqlConnection connection = new SqlConnection(GetConnectionString()))
{
string query = "SELECT I1,I2,I3,I4,I5,I6,I7,I8,I9,I10,I11,I12,I13,I14,I15 FROM LABEL_OUT WHERE LABEL_NAME='" + labelName + "'";
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
rowLines.Add(reader[0].ToString());
}
}
}
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
here rowLines will Contain all the column value such as I1,I2,.....I15
Probably the easiest way to do this is to use DbDataReader.GetValues(object[]), which populates a pre-existing array with the values from each column:
var vals = new object[reader.FieldCount];
while (reader.Read())
{
reader.GetValues(vals);
// ... do something with the values
}
If you are sure that you will take a single line you could loop on the reader using the FieldCount and add each element on a List<string>. Finally, you could just return it as an array.
var rowLines = new List<string>();
if (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
rowLines.Add(reader.IsDBNull(i) ? string.Empty : reader[i].ToString());
}
}
return rowLines.ToArray();
I'm trying to create a generic SqlDataReader which converts a table with 33 columns into a list. I would like each list item to contain all 33 column values for each row.
However, my code is assigning each value to an individual list item.
So instead of 1000 list items = 1000 rows of data, I have 33,000 list items.
I would prefer to use a list over a datatable, because the list comparisons I need to do are much simpler.
How can I have 1000 list items with 33 values each?
public static List<string> loadSQL(String query, String connectString)
{
List<string> dataList = new List<string>();
using (SqlConnection connection = new SqlConnection(connectString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i ++)
{
dataList.Add(Convert.ToString(reader.GetValue(i)));
}
}
}
}
return dataList;
}
}
... update ...
corrected to the following. It returns the list items correctly. However, my list contains 33,000 items containing 33 items each. How can I control the loop so it stops after 1000 rows?
using (SqlConnection connection = new SqlConnection(connectString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
List<string> tempRow = new List<string>();
for (int i = 0; i < reader.FieldCount; i ++)
{
tempRow.Add(Convert.ToString(reader.GetValue(i)));
}
dataList.Add(tempRow);
}
}
}
}
The best option for you to do this task is DataTable, But you don't want to use it. So, the net option will be, Create a class based on the query-output then use a List<objectOftheClass>. But in your case, the Input query will be changed all times so a common class will not be meaningful Since you are trying to make it generic. So the option you can follow is List<List<string>> or List<List<object>>. As per this the method signature will be like the following:
public static List<object[]> loadSQL(string query, string connectString)
{
List<object[]> dataList = new List<object[]>();
using (SqlConnection connection = new SqlConnection(connectString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
object[] tempRow = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
tempRow[i] = reader[i];
}
dataList.Add(tempRow);
}
}
}
}
return dataList;
}
Why List<object>? why not `List?:
The reader will give you the column data as the same type of column in the table. If it is object then you need not convert it every time.
** Note:-** Change String to string for the arguments in the method signature. You can find a reason here
You can use a List<List<string>> like this:
public static List<List<string>> loadSQL(String query, String connectString)
{
List<List<string>> dataList = new List<List<string>>();
using (SqlConnection connection = new SqlConnection(connectString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
var l = new List<string>();
for (int i = 0; i < reader.FieldCount; i ++)
{
l.Add(Convert.ToString(reader.GetValue(i)));
}
dataList.Add(l);
}
}
}
return dataList;
}
}
You can use an array within the list to achieve what you are trying to do. Here is a quick example using your code:
public static List<string[]> loadSQL(String query, String connectString)
{
List<string[]> dataList = new List<string[]>();
using (SqlConnection connection = new SqlConnection(connectString))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
int rowcounter = 0;
while (reader.Read())
{
string[] value = new string[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i ++)
{
value[i] = Convert.ToString(reader.GetValue(i));
}
dataList.Add(value);
rowcounter++;
}
}
}
return dataList;
}
Alertnately, if you want to use the List, you will need to embed the values a single string, using a comma separator or something similar.
Respected Users,
I am extracting data using data set.
I want to put value in textbox. But value is not comming.
I have following Code
try
{
da = new SqlDataAdapter("select ID from Customer where Name='" + gvBkPendingSearch.SelectedRows[0].Cells[1].Value.ToString() + "'",con);
DataSet ds = new DataSet();
da.Fill(ds);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
txtCustomerID.Text = ds.Tables[0].Rows[0].ToString();
}
catch (Exception ex)
{
}
finally
{
}
txtCustomerID is my textbox.
It is capturing value as>>>>>System.Data.DataRow
Error is in txtCustomerID.Text = ds.Tables[0].Rows[0].ToString();
but i am not able to understand it.
Please help me.
change it like this
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
txtCustomerID.Text = ds.Tables[0].Rows[i]["ID"].ToString();
The mistake you are doing is, you are accessing this
ds.Tables[0].Rows[0].ToString();
means 0th row, the whole row!! not the column value
And the datatable row is System.Data.DataRow in .Net
You need to select the column:
txtCustomerID.Text = ds.Tables[0].Rows[i][0].ToString();
Also note that you are overwriting the value of the textbox on each iteration of the loop. So what you will end up with is the ID of the last record in this textbox.
Also your query seems vulnerable to SQL injection. Personally I would recommend you scraping the DataSets in favor of an ORM or even plain old ADO.NET:
public static IEnumerable<int> GetIds(string name)
{
using (var conn = new SqlConnection("Your connection string comes here"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "select ID from Customer where Name=#Name";
cmd.Parameters.AddWithValue("#Name", name);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return reader.GetInt32(reader.GetOrdinal("ID"));
}
}
}
}
And now you could happily use this function:
string name = gvBkPendingSearch.SelectedRows[0].Cells[1].Value.ToString();
int id = GetIds(name).FirstOrDefault();
txtCustomerID.Text = id.ToString();