Is it possible to get column name only if has a value? - c#

I am having a hard time getting the codes that I need.
The code that I have created can get ALL the column names that I have listed regardless of having a value or not. What I only wanted to happen was to get the column names that has value(1).
I have this code:
internal static List<string> GetAllRoleTypeFromDatabase()
{
List<string> rolelist = new List<string>();
using (var con = new SQLiteConnection(sqliteConnectionMain.connectionString))
using (var cmd = new SQLiteCommand(con))
{
con.Open();
var _command = con.CreateCommand();
var queryq = string.Format("SELECT * FROM tblUserRoleAccess");
string commandText = queryq;
String sSQL;
sSQL = "SELECT * from tblUserRoleAccess";
cmd.CommandText = sSQL;
var dr = cmd.ExecuteReader();
for (var i = 1; i < dr.FieldCount; i++)
{
if (dr != null)
{
rolelist.Add(dr.GetName(i));
}
}
con.Close();
}
return rolelist;
}

Read a line in the reader (as i understand, there's only one row as a result).
For each column in the row check if its value is 1 (I used int, you should use the real type i.e. bool, string ...):
dr.Read();
for (var i = 1; i < dr.FieldCount; i++)
{
if (dr.GetFieldValue<int>(i) == 1)
{
rolelist.Add(dr.GetName(i));
}
}

Related

Properly read the column data type in ms access database

How to properly get the Data Type of MS Access table
Below is my code:
var con = $"Provider=Microsoft.Jet.OLEDB.4.0;" +
$"Data Source={database};" +
"Persist Security Info=True;";
using (OleDbConnection myConnection = new OleDbConnection())
{
myConnection.ConnectionString = con;
myConnection.Open();
DataTable dt = myConnection.GetSchema("Tables");
var l = myConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
var isTableExist = false;
foreach (DataRow item in l.Rows)
{
var tbleName = item[2].ToString();
if (tbleName == tableName)
{
isTableExist = true;
break;
}
}
if (isTableExist)
{
string sql = string.Format($"SELECT * FROM {tableName}");
using (OleDbCommand cmd = new OleDbCommand(sql, myConnection))
{
using (OleDbDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
for (int i = 0; i < reader.FieldCount; i++)
{
Console.WriteLine(reader.GetName(i));
Console.WriteLine(reader.GetDataTypeName(i));
}
}
}
}
}
}
Here is the structure of the mdb file im reading
And this is what i'm receiving
id
DBTYPE_I4
main_id
DBTYPE_I4
Document_ID
DBTYPE_WVARCHAR
End_page
DBTYPE_WVARCHAR
No_pages
DBTYPE_I4
Why does the AutoNumber datatype show the same as the number data type?
What i'm doing here is merging tables. And i want to skip the insert statement for those data type AutoNumber but i can't make it work because the result is the same with number. Thank you

SqlDataReader closed for unknown reason

C# noob here. I am trying to get some data from a SQL Data Base using the code below, however i get the error: System.InvalidOperationException: 'Invalid attempt to call Read when reader is closed.'
After searching for the answer online, i found nothing, maybe someone can see what is wrong?
The error happens at: while (rdr.Read())
Thank you!
internal List<string> GetInflationByYearData(string Country, int StartYear,
int EndYear)
{
string CS =
ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("SpCountryData", con)
{
CommandType = System.Data.CommandType.StoredProcedure
};
cmd.Parameters.AddWithValue("#act",
"getInflationByYearData");
cmd.Parameters.AddWithValue("#Country", Country);
cmd.Parameters.AddWithValue("#startYear", StartYear);
cmd.Parameters.AddWithValue("#endYear", EndYear);
var table = new DataTable();
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
{
table.Load(rdr);
};
}
//con.Close();
List<string> labelList = new List<string>();
List<string> valueList = new List<string>();
if (table.Rows.Count > 0)
{
foreach (DataRow row in table.Rows)
{
string label = row["Year"].ToString();
string value = row["Percentage"].ToString();
labelList.Add(label);
valueList.Add(value);
}
}
List<string> list = new List<string>();
StringBuilder sbLabels = new StringBuilder();
foreach (string lbl in labelList)
{
sbLabels.Append(lbl + ",");
}
StringBuilder sbValues = new StringBuilder();
foreach (string val in valueList)
{
sbValues.Append(val + ",");
}
list.Add(sbLabels.ToString().Substring(0, sbLabels.Length -
1));
list.Add(sbValues.ToString().Substring(0, sbValues.Length -
1));
return list;
}
}
Load consumes the reader to completion; you should either have a while (rdr.Read()) loop, or call table.Load(rdr), but: not both. Load basically does that same loop internally.
So: remove the loop - just use Load.
However! If all you want is the data as List<string>, loading it into a DataTable seems like an unnecessary step (DataTable is not lightweight) - it seems like you could do that in the reader, or perhaps use other tools (like "dapper") to remove that.
It isn't clear what data types Year and Percentage are, but as a "dapper" example...
class MyRowThing {
public int Year {get;set;}
public decimal Percentage {get;set;}
}
var rawData = con.Query<MyRowThing>("SpCountryData",
new { // params here
act = "getInflationByYearData", Country,
startYear = StartYear, endYear = EndYear
}, commandType: CommandType.StoredProcedure).AsList();
// now loop over rawData, which is a List<MyRowThing> with the data
Replacing:
var table = new DataTable();
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
{
table.Load(rdr);
};
}
//con.Close();
List<string> labelList = new List<string>();
List<string> valueList = new List<string>();
if (table.Rows.Count > 0)
{
foreach (DataRow row in table.Rows)
{
string label = row["Year"].ToString();
string value = row["Percentage"].ToString();
labelList.Add(label);
valueList.Add(value);
}
}
With:
con.Open();
List<string> labelList = new List<string>();
List<string> valueList = new List<string>();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
labelList.Add(rdr["Year"].ToString());
valueList.Add(rdr["Percentage"].ToString());
}
Will get rid of the DataTable for a more optimized code.

Why do my query won't get all my data ? C# Access

After an hour of debugging I am trying to find why my Query returns only 1 ID where there are at least 3:
public static string[] selectAGIdOfKC(string id)
{
int nbAg = 0;
DataTable results = new DataTable();
using (OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=bdd.mdb;
Persist Security Info=False;"))
{
OleDbCommand cmd = new OleDbCommand("SELECT Id FROM ActionG WHERE Num_Kc = #Id", conn);
conn.Open();
cmd.Parameters.AddWithValue("#Id", id);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
conn.Close();
adapter.Fill(results);
nbAg=results.Rows[0].ItemArray.Count();
}
string[] myTab = new string[nbAg];
for (int i = 0; i < nbAg; i++)
{
myTab[i] = results.Rows[0].ItemArray[i].ToString();
}
return myTab;
}
I tried to use some workarounds but nothing solves the problem of the missing returned IDs...
Can anyone help me ? Thanks for your time!
It all depends on how you want the results, but assuming that you want nbAg to contain the number of rows returned, and assuming that you want myTab to contain the id-values returned, your code is not written to do what you want.
Please note the ellipsis ... - I have only modified the code that was causing your current symptoms.
public static string[] selectAGIdOfKC(string id)
{
int nbAg = 0;
...
nbAg = results.Rows.Count();
string[] myTab = new string[nbAg];
for (int i = 0; i < nbAg; i++)
{
myTab[i] = results.Rows[i][0].ToString();
// This is the first column of row i
}
return myTab;
}

Add full row to DataTable MVC4

i'm new to MVC and I am trying to build a DataTable from a stored procedure response and pass it back to my View. For the rows I build a comma delimited string full of cell values.
The issue I am having is that the string is not getting parsed by the commas, and effectively it is passing the whole string into the first cell of each row.
What is the correct way to build up a row comprised of the individual values for each column? The number of columns, their names, and amount of records returned are all variable.
public ActionResult dataSet(string table, string key, string search)
{
SqlDataReader rdr = null;
SqlConnection con = new SqlConnection("Connection stuff");
SqlCommand cmd = new SqlCommand();
cmd = new SqlCommand("dbo.USP_getDataSet", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#key", key);
cmd.Parameters.AddWithValue("#table", table);
cmd.Parameters.AddWithValue("#search", search);
con.Open();
DataTable theTable = new DataTable();
try
{
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
int count = rdr.FieldCount;
string rowString = "";
int intRows = theTable.Columns.Count;
//Build columns on first pass through
if (intRows == 0){
for (int i = 0; i < count; i++){
theTable.Columns.Add(Convert.ToString(rdr.GetName(i).TrimEnd()), typeof(string));
}
}
//Grab all values for each column
for (int i = 0; i < count; i++){
rowString += '\"' + (Convert.ToString(rdr.GetValue(i)).TrimEnd()) + '\"' + ", ";
}
//Remove trailing delimiter
string finishedRow = rowString.Substring(0, rowString.Length - 2);
//Add the full row for each time through reader
theTable.Rows.Add(finishedRow);
}
}
finally
{
if (rdr != null)
{ rdr.Close(); }
if (con != null)
{ con.Close(); }
}
return View(theTable);
}
According to the documentation for the DataRowCollection.Add(params Object[] values) method, each value passed in will populate each cell. Since you are passing in a single value, it is the value of the cell.
You probably want:
var cells = new object[count];
for (int i = 0; i < count; i++)
{
cells[i] = rdr.GetString(i).Trim() + "\"
}
theTable.Rows.Add(cells)

Can you get the column names from a SqlDataReader?

After connecting to the database, can I get the name of all the columns that were returned in my SqlDataReader?
var reader = cmd.ExecuteReader();
var columns = new List<string>();
for(int i=0;i<reader.FieldCount;i++)
{
columns.Add(reader.GetName(i));
}
or
var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
There is a GetName function on the SqlDataReader which accepts the column index and returns the name of the column.
Conversely, there is a GetOrdinal which takes in a column name and returns the column index.
You can get the column names from a DataReader.
Here is the important part:
for (int col = 0; col < SqlReader.FieldCount; col++)
{
Console.Write(SqlReader.GetName(col).ToString()); // Gets the column name
Console.Write(SqlReader.GetFieldType(col).ToString()); // Gets the column type
Console.Write(SqlReader.GetDataTypeName(col).ToString()); // Gets the column database type
}
Already mentioned. Just a LINQ answer:
var columns = reader.GetSchemaTable().Rows
.Cast<DataRow>()
.Select(r => (string)r["ColumnName"])
.ToList();
//Or
var columns = Enumerable.Range(0, reader.FieldCount)
.Select(reader.GetName)
.ToList();
The second one is cleaner and much faster. Even if you cache GetSchemaTable in the first approach, the querying is going to be very slow.
If you want the column names only, you can do:
List<string> columns = new List<string>();
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly))
{
DataTable dt = reader.GetSchemaTable();
foreach (DataRow row in dt.Rows)
{
columns.Add(row.Field<String>("ColumnName"));
}
}
But if you only need one row, I like my AdoHelper addition. This addition is great if you have a single line query and you don't want to deal with data table in you code. It's returning a case insensitive dictionary of column names and values.
public static Dictionary<string, string> ExecuteCaseInsensitiveDictionary(string query, string connectionString, Dictionary<string, string> queryParams = null)
{
Dictionary<string, string> CaseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
try
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
// Add the parameters for the SelectCommand.
if (queryParams != null)
foreach (var param in queryParams)
cmd.Parameters.AddWithValue(param.Key, param.Value);
using (SqlDataReader reader = cmd.ExecuteReader())
{
DataTable dt = new DataTable();
dt.Load(reader);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
{
CaseInsensitiveDictionary.Add(column.ColumnName, row[column].ToString());
}
}
}
}
conn.Close();
}
}
catch (Exception ex)
{
throw ex;
}
return CaseInsensitiveDictionary;
}
Use an extension method:
public static List<string> ColumnList(this IDataReader dataReader)
{
var columns = new List<string>();
for (int i = 0; i < dataReader.FieldCount; i++)
{
columns.Add(dataReader.GetName(i));
}
return columns;
}
For me, I would write an extension method like this:
public static string[] GetFieldNames(this SqlDataReader reader)
{
return Enumerable.Range(0, reader.FieldCount).Select(x => reader.GetName(x)).ToArray();
}
I use the GetSchemaTable method, which is exposed via the IDataReader interface.
You sure can.
protected void GetColumNames_DataReader()
{
System.Data.SqlClient.SqlConnection SqlCon = new System.Data.SqlClient.SqlConnection("server=localhost;database=northwind;trusted_connection=true");
System.Data.SqlClient.SqlCommand SqlCmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Products", SqlCon);
SqlCon.Open();
System.Data.SqlClient.SqlDataReader SqlReader = SqlCmd.ExecuteReader();
System.Int32 _columncount = SqlReader.FieldCount;
System.Web.HttpContext.Current.Response.Write("SqlDataReader Columns");
System.Web.HttpContext.Current.Response.Write(" ");
for ( System.Int32 iCol = 0; iCol < _columncount; iCol ++ )
{
System.Web.HttpContext.Current.Response.Write("Column " + iCol.ToString() + ": ");
System.Web.HttpContext.Current.Response.Write(SqlReader.GetName( iCol ).ToString());
System.Web.HttpContext.Current.Response.Write(" ");
}
}
This is originally from: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik
It is easier to achieve it in SQL
var columnsList = dbContext.Database.SqlQuery<string>("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'SCHEMA_OF_YOUE_TABLE' AND TABLE_NAME = 'YOUR_TABLE_NAME'").ToList();

Categories