More efficient way to iterate on my data (DbReader/DataSet) - c#

I'm working on a project in C# that converts a database table to an XML-file with base64 encoded contents. Please bear with me, because C# is not my day-to-day programming language.
The code I've managed to come up with is this:
OdbcCommand DbCommand = DbConnection.CreateCommand();
DbCommand.CommandText = "SELECT * FROM " + dbTable;
OdbcDataReader DbReader = DbCommand.ExecuteReader();
int fCount = DbReader.FieldCount;
string[] colnames = new string[fCount];
output += "<" + dbTable + ">\n";
for (int i = 0; i < fCount; i++)
{
string fName = DbReader.GetName(i);
colnames[i] = fName.ToString();
}
while (DbReader.Read())
{
output += "\t<export_row>\n";
for (int i = 0; i < fCount; i++)
{
string col = "";
try
{
col = DbReader.GetString(i);
}
catch (Exception) { }
if (col.ToString().Length > 0 || i == 0)
{
output += "\t\t<" + colnames[i] + ">" + Base64Encode(col).ToString() + "</" + colnames[i] + ">\n"; ;
}
}
output += "\t</export_row>\n";
}
output += "</" + dbTable + ">\n";
The problem is, that even with a relatively small table, this causes the application to choke up and run extremely slowly. The obvious clue is that there's an enormous amount of iterations involved for each row, so I have been looking for a solution to this problem. I have tried using a DataSet, which seemed to increase performance slightly, but not significantly enough.
connection.Open();
adapter.Fill(dataSet);
output += "<" + dbTable + ">\n";
foreach (DataTable table in dataSet.Tables)
{
foreach (DataRow row in table.Rows)
{
output += "\t<export_row>\n";
foreach (DataColumn column in table.Columns)
{
output += "\t\t<" + column.ToString() + ">" + Base64Encode(row[column].ToString()).ToString() + "</" + column.ToString() + ">\n"; ;
}
output += "\t</export_row>\n";
}
}
output += "</" + dbTable + ">\n";
However, the problem remains that there is no other way than iterating through all the columns each and every time. Which begs the question: isn't there a more efficient way to do this? I'm not going to make a model for every table, because there are hundreds of tables in this database and the power would be the flexibility of transferring data in this way.
Can someone help me out, or point me in the right direction? For example, is there a way to extract both the column and the value at the same time? As in: foreach(row as key => value) or something. That would drastically reduce the amount of iterations required.
Thanks in advance for thinking along! There must be something (obvious) I missed.

The key is always not to write formatting of text formats yourself be it HTML, JSON, XML, YAML, or anything else. This is just asking for hard-to-find bugs and injections since you do not have control of the data or table names. For example, what happens if your data contains !, <, or >?
C# has numerous built-in XML tools and so does SQL where the formatting is done for you. Which one to use would depend on your other requirements or preferences.
SqlCommand.ExecuteXmlReader
string cmd = "SELECT * FROM " + myTable + " FOR XML AUTO";
using (SqlCommand k = new SqlCommand(cmd, c))
{
c.Open();
XmlReader xml = k.ExecuteXmlReader();
Console.WriteLine(xml);
c.Close();
}
DataTable.WriteXml
string ConString = "your connection string";
string CmdString = "SELECT * FROM " + myTable;
SqlConnection con;
SqlCommand cmd;
SqlDataAdapter sda;
DataTable dt;
using (con = new SqlConnection(ConString))
{
cmd = new SqlCommand(CmdString, con);
con.Open();
dt = new DataTable(tableName);
sda = new SqlDataAdapter(cmd);
sda.Fill(dt);
dt.WriteXml(tableName + ".xml");
con.Close();
}
DataSet.GetXml()
// Create a DataSet with one table containing
// two columns and 10 rows.
DataSet dataSet = new DataSet("dataSet");
DataTable table = dataSet.Tables.Add("Items");
table.Columns.Add("id", typeof(int));
table.Columns.Add("Item", typeof(string));
// Add ten rows.
DataRow row;
for(int i = 0; i <10;i++)
{
row = table.NewRow();
row["id"]= i;
row["Item"]= "Item" + i;
table.Rows.Add(row);
}
// Display the DataSet contents as XML.
Console.WriteLine(dataSet.GetXml());

Related

How do I display a select from database consisting of multiple join in a text box?

I have to do a select from database that have multiple join( i will show you belong) and i put in one command . The problem it is next one : a select something from a table and when i run the code it tell me something like that : " Column '....' does not belong to table ." and i look into table and it is. I will put code for take a look. Do you have any idea? I am sure i do something wrong but i don t know what.
string connectionString = "Data Source=..." +
"User=..." +
"Password=..";
OracleConnection con = new OracleConnection();
con.ConnectionString = connectionString;
con.Open();
string select3 = "SELECT tblOwner.OwnerFirstName , tblOwner.OwnerLastName, tblOwner.OwnerEmailID, tblOwner.OwnerLoc, tblDomain.DomainName " +
" FROM tblDomain " +
" INNER JOIN(tblOwner INNER JOIN tblProductInfo ON tblOwner.OwnerID = tblProductInfo.OwnerID) ON tblDomain.DomainIDShort = tblOwner.DomainID" +
" WHERE(((tblProductInfo.Productname) = ' "+ mystring +
"'" + "))";
OracleDataAdapter aa = new OracleDataAdapter(select3, con);
DataTable cc = new DataTable();
bb.Fill(cc);
foreach (DataRow ww in dt.Rows)
{
textBox2.Text = (ww["DomainName"].ToString());
}
Your DataTable seems to not have a column called "DomainName". You can use the following code to list the existing column names in the output window of visual studio.
foreach (DataColumn col in cc.Columns)
{
Debug.WriteLine(col.ColumnName);
}
First: You are filling DataTable from different data adapter.
OracleDataAdapter aa = new OracleDataAdapter(select3, con); // aa created
DataTable cc = new DataTable();
bb.Fill(cc); // 'bb' fills data
Second: You are reading data from different DataTable, not that which you are filling with data.
DataTable cc = new DataTable();
bb.Fill(cc); // 'cc' variable filled with data
foreach (DataRow ww in dt.Rows) // reading rows from 'dt' variable
{
textBox2.Text = (ww["DomainName"].ToString());
}

how to run sql query on all column data and export result to csv -in c#

I made sql queries on an access DB. In datagridview2 i see in the first column the istalled programs in the second how many computers are installed that program.
col1 col2
xxxx 1
yyyy 2
zzzz 3
OleDbCommand command2 = new OleDbCommand();
command2.Connection = connection;
string query = "SELECT Item_1, count(Item_1) FROM (SELECT Item_1 FROM Audit_data where Category_ID = 500) group by Item_1 having (count(*)>0) ";
command2.CommandText = query;
OleDbDataAdapter da1 = new OleDbDataAdapter(command2);
da1.Fill(dt2);
dataGridView2.DataSource = dt2;
dataGridView2.AutoResizeColumns();
The datagridview3 contains only the computers name where the programs are installed when the selection is changed on datagridview2:
string selcell = Convert.ToString(dataGridView2.CurrentCell.Value);
OleDbCommand command3 = new OleDbCommand();
command3.Connection = connection;
string query = "select distinct Fully_Qualified_Domain_Name from Audit_Data, Computer_master where Item_1= '"+selcell+"' and category_id=500 and Audit_Data.computer_id = Computer_master.computer_id ";
command3.CommandText = query;
OleDbDataAdapter da3 = new OleDbDataAdapter(command3);
da3.Fill(dt3);
dataGridView3.DataSource = dt3;
dataGridView3.AutoResizeColumns();
And i would like to run these queries to get all software with all installed computer names. I don't know how to run query on all data on col 1 and export it to csv like this.
xxxx; 1; qwer_pc
yyyy; 2; asdf_pc;
qwer_pc
zzzz; 3; asdf_pc;
qwer_pc;
yxcv_pc
Could anyone help to solve this problem?
Or can i somehow combine the two queries?
The solution was easier than i thought:
SELECT distinct Item_1,Fully_Qualified_Domain_Name FROM Audit_data,Computer_master where Category_ID = 500 and Audit_data.computer_id = Computer_master.Computer_id
The CSV export is the following :
string csv = string.Empty;
//Add the Header row for CSV file.
foreach (DataGridViewColumn column in dataGridView4.Columns)
{
csv += column.HeaderText + ',';
}
//Add new line.
csv += "\r\n";
//Adding the Rows
foreach (DataGridViewRow row in dataGridView4.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
//Add the Data rows.
csv += cell.Value.ToString().Replace(",", ";") + ',';
}
//Add new line.
csv += "\r\n";
}
//Exporting to CSV.
string folderPath = txt_csv_exp_path.Text;
File.WriteAllText(folderPath +txt_exp_file_name.Text +" .csv", csv);
MessageBox.Show("CSV file saved.");

Can't export large data from oracle to excel file using c#

I have a problem with extracting large data from oracle table to C#, and I
couldn't find the solution myself.
For this task I wrote a C# code, which loaded data from oracle procedure, which returns cursor, in excel file for the first time.
But when I tried to load bigger table (about 20 columns and 90 000 rows), it just didn't work.
Script doesn't fall with error, but data are not inserted into excel file.
I tried to load for 10 000 rows and then save the results, but again, only 30 000 rows were inserted.
I monitored the counter in loop, it is going correct and reach needed 90 000 and ExecuteNonQuery() always returned the value 10 000. But when I open excel file, there are only 30 000 rows there.
Can you please help me to catch the error, or may be somebody met the same problem, and can advise me what to do or what to read.
Thank you for any help!
I didn't write the connection string, but I think, it's correct, cause script works correctly with small datatable.
public static void Main()
{
string datetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
try
{
OleDbConnection Excel_OLE_Con = new OleDbConnection();
OleDbCommand Excel_OLE_Cmd = new OleDbCommand();
string qwe_constr = "connection string";
OracleConnection myADONETConnection = new OracleConnection(qwe_constr);
string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + "E:\\qaz\\15.07.2016\\qwe" +
";" + "Extended Properties=\"Excel 12.0 Xml;HDR=YES;\"";
File.Delete("E:\\qaz\\15.07.2016\\qwe.xlsx");
//fill datatable with data for insert
myADONETConnection.Open();
OracleCommand cmd_proc = new OracleCommand();
cmd_proc.Connection = myADONETConnection;
cmd_proc.CommandType = System.Data.CommandType.StoredProcedure;
cmd_proc.CommandText = "procedure_name";
cmd_proc.Parameters.Add("p_show_del", OracleDbType.Int16).Value = 0;
cmd_proc.Parameters.Add("p_type", OracleDbType.Varchar2, 3).Value = "INV";
cmd_proc.Parameters.Add("p_errno", OracleDbType.Int16).Value = 157;
cmd_proc.Parameters.Add("outcur", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
DataTable dt_with_data = new DataTable();
dt_with_data.Load(cmd_proc.ExecuteReader());
myADONETConnection.Close();
//string with column headers
string TableColumns = "";
foreach (DataColumn column in dt_with_data.Columns)
{
TableColumns += column + "],[";
}
// Replace most right comma from Columnlist
TableColumns = ("[" + TableColumns.Replace(",", " Text,").TrimEnd(','));
TableColumns = TableColumns.Remove(TableColumns.Length - 2);
//Use OLE DB Connection and Create Excel Sheet
Excel_OLE_Con.ConnectionString = connstring;
Excel_OLE_Con.Open();
Excel_OLE_Cmd.Connection = Excel_OLE_Con;
Excel_OLE_Cmd.CommandText = "Create table [sheet1] (" + TableColumns + ")";
Excel_OLE_Cmd.ExecuteNonQuery();
Excel_OLE_Con.Close();
//Write Data to Excel Sheet from DataTable dynamically
//string with command
Excel_OLE_Con.Open();
String sqlCommandInsert = "";
String sqlCommandValue = "";
foreach (DataColumn dataColumn in dt_with_data.Columns)
{
sqlCommandValue += dataColumn + "],[";
}
sqlCommandValue = "[" + sqlCommandValue.TrimEnd(',');
sqlCommandValue = sqlCommandValue.Remove(sqlCommandValue.Length - 2);
sqlCommandInsert = "INSERT into [sheet1] (" + sqlCommandValue + ") VALUES(";
int columnCount = dt_with_data.Columns.Count;
int i_qaz = 0;
foreach (DataRow row in dt_with_data.Rows)
{
i_qaz++;
Console.WriteLine(i_qaz.ToString());
string columnvalues = "";
for (int i = 0; i < columnCount; i++)
{
int index = dt_with_data.Rows.IndexOf(row);
columnvalues += "'" + dt_with_data.Rows[index].ItemArray[i].ToString().Replace("'", "''") + "',";
}
columnvalues = columnvalues.TrimEnd(',');
var command = sqlCommandInsert + columnvalues + ")";
Excel_OLE_Cmd.CommandText = command;
Excel_OLE_Cmd.ExecuteNonQuery();
}
}
catch (Exception exception)
{
// Create Log File for Errors
using (StreamWriter sw = File.CreateText("E:\\qaz\\15.07.2016\\qwe_" + datetime + ".log"))
{
sw.WriteLine(exception.ToString());
}
}
}
PS: Same question in Russian.

How to present the data from multiple DataTables in a series of stacked data grids?

I have an undefined amount of DataTables. I get them from my DataBase, each DataTable stands for one Table in my DataBase, I dont use all Tables of the DataBase just the few I need (these were selectet earlier in the code) and not all columns (same like the tables).
Now my problem: I want to show them in a DataGrid one below the other with breaks between them for the tablename.
This is how i get my DataTables:
List<DBTable> selectedTbl = DBObject.SingDBObj.GetSelectedTables();
foreach (DBTable tbl in selectedTbl)
{
string cols = tbl.GetSelectedColumnNames();
string query = #"SELECT " + cols + " FROM [" + DBObject.SingDBObj.DataSource + "].[" + DBObject.SingDBObj.Database + "].[" + tbl.Schema + "].[" + tbl.Name + "];";
DataTable DTShow = DBObject.SingDBObj.ExecuteQuery(query);
}
dataGridShowColmns.DataContext = ??;
Is there an easy way to do this?
You maybe mean something like:
DataSet ds = new DataSet();
// dataset is here just initialized for demonstration, you would first
// get the tables from database and populate dataset
for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable dt = ds.Tables[i];
foreach (DataRow dr in dt.Rows)
{
dataGridView1.Rows.Add(dr);
}
}
In SQL name to a dataset cannot be assigned, only way you can do it in c#/VB. like
Dataset.Table[0].Name = "MyTable";

Sql DataBinding Against Reading Label/Textbox.text

I am trying to bind sql data on textboxes against reading data from label my code is as below:
string sql1 = " select openbal from AccountMast where accname='" + comboBox1.Text + "' and companyID='" + label4.Text + "'";
SqlDataAdapter dap1 = new SqlDataAdapter(sql1, con);
DataSet ds1 = new DataSet();
dap1.Fill(ds1);
for (int p = 0; p < ds1.Tables[0].Rows.Count; p++)
{
if (label11.Text == "Dr")
{
txtopenbaldr.Text = Convert.ToString(ds1.Tables[0].Rows[p]["openbal"]);
}
if (label11.Text == "Cr")
{
txtopenbalcr.Text = Convert.ToString(ds1.Tables[0].Rows[p]["openbal"]);
}
}
//Label11 Bind by Sql.
string sql10 = " select obcat from AccountMast where accname='" + comboBox1.Text + "' and companyID='" + label4.Text + "'";
SqlDataAdapter dap10 = new SqlDataAdapter(sql10, con);
DataSet ds10 = new DataSet();
dap10.Fill(ds10);
for (int p = 0; p < ds10.Tables[0].Rows.Count; p++)
{
label11.Text = Convert.ToString(ds10.Tables[0].Rows[p]["obcat"]);
}
The label11 bound by sql data and it should display text "Dr" OR "Cr" at a time.
but it's not working as the label11.text not support for bind the data onto textboxes
I have two textboxes as below:
Opening Balance/Debit Opening Balance/Credit
txtopenbaldr.Text txtopenbalcr.Text
There are two textboxes which can databind on above condition: Remember only one textbox should be bind as per condition.
I am trying the trick but it's fail. Suggest the solution.
I'm assuming that you simply appended the code for label11.text at the end of your message, but that in reality label11.text is assigned before you try to set txtopenbaldr.Text or txtopenbalcr.Text.
If that's the case, I would make sure that label11.Text actually has the value Dr or Cr, and not DR or CR, as the comparisons will be case-sensitive.

Categories