Copy multiple column values from SqlReader to array? - c#

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();

Related

How do I read SQL row values of a column into an array?

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();

Select SQL Server C# and Array with return [duplicate]

I have a SQL Server 2008 database and I am working on it in the backend. I am working on asp.net/C#
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//how do I read strings here????
}
I know that the reader has values. My SQL command is to select just 1 column from a table. The column contains strings ONLY. I want to read the strings (rows) in the reader one by one. How do I do this?
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var myString = rdr.GetString(0); //The 0 stands for "the 0'th column", so the first column of the result.
// Do somthing with this rows string, for example to put them in to a list
listDeclaredElsewhere.Add(myString);
}
}
string col1Value = rdr["ColumnOneName"].ToString();
or
string col1Value = rdr[0].ToString();
These are objects, so you need to either cast them or .ToString().
Put the name of the column begin returned from the database where "ColumnName" is. If it is a string, you can use .ToString(). If it is another type, you need to convert it using System.Convert.
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string column = rdr["ColumnName"].ToString();
int columnValue = Convert.ToInt32(rdr["ColumnName"]);
}
while(rdr.Read())
{
string col=rdr["colName"].ToString();
}
it wil work
Thought to share my helper method for those who can use it:
public static class Sql
{
public static T Read<T>(DbDataReader DataReader, string FieldName)
{
int FieldIndex;
try { FieldIndex = DataReader.GetOrdinal(FieldName); }
catch { return default(T); }
if (DataReader.IsDBNull(FieldIndex))
{
return default(T);
}
else
{
object readData = DataReader.GetValue(FieldIndex);
if (readData is T)
{
return (T)readData;
}
else
{
try
{
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
}
}
}
Usage:
cmd.CommandText = #"SELECT DISTINCT [SoftwareCode00], [MachineID]
FROM [CM_S01].[dbo].[INSTALLED_SOFTWARE_DATA]";
using (SqlDataReader data = cmd.ExecuteReader())
{
while (data.Read())
{
usedBy.Add(
Sql.Read<String>(data, "SoftwareCode00"),
Sql.Read<Int32>(data, "MachineID"));
}
}
The helper method casts to any value you like, if it can't cast or the database value is NULL, the result will be null.
For a single result:
if (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
For multiple results:
while (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
I know this is kind of old but if you are reading the contents of a SqlDataReader into a class, then this will be very handy. the column names of reader and class should be same
public static List<T> Fill<T>(this SqlDataReader reader) where T : new()
{
List<T> res = new List<T>();
while (reader.Read())
{
T t = new T();
for (int inc = 0; inc < reader.FieldCount; inc++)
{
Type type = t.GetType();
string name = reader.GetName(inc);
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
if (name == prop.Name)
{
var value = reader.GetValue(inc);
if (value != DBNull.Value)
{
prop.SetValue(t, Convert.ChangeType(value, prop.PropertyType), null);
}
//prop.SetValue(t, value, null);
}
}
}
res.Add(t);
}
reader.Close();
return res;
}
I would argue against using SqlDataReader here; ADO.NET has lots of edge cases and complications, and in my experience most manually written ADO.NET code is broken in at least one way (usually subtle and contextual).
Tools exist to avoid this. For example, in the case here you want to read a column of strings. Dapper makes that completely painless:
var region = ... // some filter
var vals = connection.Query<string>(
"select Name from Table where Region=#region", // query
new { region } // parameters
).AsList();
Dapper here is dealing with all the parameterization, execution, and row processing - and a lot of other grungy details of ADO.NET. The <string> can be replaced with <SomeType> to materialize entire rows into objects.
Actually, I figured it out myself that I could do this:
while (rdr.read())
{
string str = rdr.GetValue().ToString().Trim();
}
In the simplest terms, if your query returns column_name and it holds a string:
while (rdr.Read())
{
string yourString = rdr.getString("column_name")
}
I usually read data by data reader this way. just added a small example.
string connectionString = "Data Source=DESKTOP-2EV7CF4;Initial Catalog=TestDB;User ID=sa;Password=tintin11#";
string queryString = "Select * from EMP";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
reader.Close();
}
}
You have to read database columnhere. You could have a look on following code snippet
string connectionString = ConfigurationManager.ConnectionStrings["NameOfYourSqlConnectionString"].ConnectionString;
using (var _connection = new SqlConnection(connectionString))
{
_connection.Open();
using (SqlCommand command = new SqlCommand("SELECT SomeColumnName FROM TableName", _connection))
{
SqlDataReader sqlDataReader = command.ExecuteReader();
if (sqlDataReader.HasRows)
{
while (sqlDataReader.Read())
{
string YourFirstDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
string YourSecondDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
string YourThridDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
}
}
sqlDataReader.Close();
}
_connection.Close();
I have a helper function like:
public static string GetString(object o)
{
if (o == DBNull.Value)
return "";
return o.ToString();
}
then I use it to extract the string:
tbUserName.Text = GetString(reader["UserName"]);

How to query a C# list against a database table

My code isn't returning any rows from a test database table when I pass a string version of a list, but it does return rows if I pass the list members in directly.
When I use a message box to show the string joinedSerialsList, it appears to be formatted properly.
// Create comma delimited list of serials:
int currentSerial = beginning;
List<string> serialsList = new List<string>();
for (int i = 0; i < count; i++)
{
serialsList.Add(currentSerial.ToString());
currentSerial++;
}
string joinedSerialsList = string.Format("({0})", string.Join(", ", serialsList));
OleDbConnection connection = BadgeDatabaseDB.GetConnection();
string checkStatement
= "SELECT SerialNumber, OrderNumber "
+ "FROM SerialNumbersMFG "
+ "WHERE SerialNumber IN (#List)";
OleDbCommand command = new OleDbCommand(checkStatement, connection);
command.Parameters.AddWithValue("#List", joinedSerialsList);
string duplicateSerials = "";
try
{
connection.Open();
OleDbDataReader dataReader = command.ExecuteReader();
if (dataReader.Read())
{
duplicateSerials += dataReader["OrderNumber"].ToString() + "\n";
}
}
catch (OleDbException ex)
{
throw ex;
}
finally
{
connection.Close();
}
return duplicateSerials;
I rewrited your sample, this work:
private IEnumerable<string> getData()
{
// Create comma delimited list of serials:
int currentSerial = 4452; // your constant
var serialsList = new List<int>();
var count = 100;
for (int i = 0; i < count; i++)
serialsList.Add(currentSerial++);
var connString = getConnectionString();
var results = new List<string>();
string sqlSelect = $"SELECT SerialNumber, OrderNumber FROM SerialNumbersMFG WHERE SerialNumber IN ({string.Join(",", serialsList)})";
using (var connection = new SqlConnection(connString)) // BadgeDatabaseDB.GetConnection();
{
using (var command = new SqlCommand(sqlSelect, connection))
{
connection.Open();
var dataReader = command.ExecuteReader();
while (dataReader.Read())
results.Add(dataReader["OrderNumber"].ToString());
}
}
return results;
}

Returning Data Rows to List<string> with SqlDataReader

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.

Edit one list along with others in list of lists

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;

Categories

Resources