My C# application is significantly slower than I would like. The program accesses an Excel sheet and loops through each row on a sheet / does the following:
Collects variables from that row
Creates an SQL query based off those variables
Executes that query
then a reader goes out and puts it in its proper column on that same row.
*Note, each row has 6 different SQL queries/ final numbers that are calculated and input into the sheet, the code below is just showing the first 2 for brevity's sake. The sheet has around 300 rows, so the program is executing 300 * 6= 1,800 SQL queries each time its run. For each one of those 1,800 numbers, the program is accessing the sheet and inputting it into the sheet.
Instead of doing the excelWorksheet.get_Range and inputting the number into the Excel sheet for each number, one at a time, would it be faster to store each number into an array and then go back later and mass dump all of the numbers into the sheet, once all of the queries have been executed and the array is full?
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = "Data Source=WRDXPVSEPIRPT00;DATABASE=Epicor905;Workstation ID=SMEBPPL204TN;Trusted_Connection=true";
try
{
//initiate the connection
conn.Open();
}
catch(SqlException ex)
{
throw new ApplicationException(string.Format("You're not connected to the database, please close the program, re-connect to the network, and try again."), ex);
}
progressBar1.Value = 60;
statusLabel.Text = "Retrieving account balances from database...";
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//iterate through each row and pull information
for (int i = 2; i < lastUsedRow + 1; i++)
{
//string iString = Convert.ToString(i);
statusLabel.Text = "Retrieving balances for " + i + " of " + lastUsedRow + " accounts...";
//declare excel sheet range variables
var CompanyVar = excelWorksheet.get_Range("A" + i, "A" + i).Text;
var FiscalYear = excelWorksheet.get_Range("B" + i, "B" + i).Text;
var FiscalPeriod = excelWorksheet.get_Range("C" + i, "C" + i).Text;
var segValue1 = excelWorksheet.get_Range("F" + i, "F" + i).Text;
var segValue2 = excelWorksheet.get_Range("G" + i, "G" + i).Text;
var segValue3 = excelWorksheet.get_Range("H" + i, "H" + i).Text;
int FiscalYearHelper = Convert.ToInt32(FiscalYear);
var FiscalYearPYY = FiscalYearHelper - 1;
//begin filling in CY YTD column
string SQLCode = "SELECT SUM(DebitAmount-CreditAmount) as BalanceAmt FROM GLJrnDtl WITH (NOLOCK) WHERE" +
" FiscalPeriod between 1 AND " + FiscalPeriod + "AND Company =" + "'" + CompanyVar + "'" +
"AND FiscalYear =" + "'" + FiscalYear + "'" + "AND SegValue1 LIKE " + "'" + segValue1 + "'" +
"AND SegValue2 LIKE " + "'" + segValue2 + "'" + "AND SegValue3 LIKE " + "'" + segValue3 + "'";
SqlCommand command = new SqlCommand(SQLCode, conn);
// Create new SqlDataReader object and read data from the command.
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string cyAct = reader["BalanceAmt"].ToString();
if (cyAct == "")
{
goto CYM;
//cyAct = "0.00";
}
var cyAct1 = (float)Convert.ToDouble(cyAct);
int one = Convert.ToInt32(excelWorksheet.get_Range("E" + i, "E" + i).Text);
double cyAct2 = (cyAct1 * one);
string cyAct3 = cyAct2.ToString("0.##");
excelWorksheet.get_Range("I" + i, "I" + i).Value = cyAct3;
}
}
//end filling in column
//begin filling in CY Month column
CYM:
string SQLCodeMonth = "SELECT SUM(DebitAmount-CreditAmount) as BalanceAmt FROM GLJrnDtl WITH (NOLOCK) WHERE" +
" FiscalPeriod = " + FiscalPeriod + "AND Company =" + "'" + CompanyVar + "'" +
"AND FiscalYear =" + "'" + FiscalYear + "'" + "AND SegValue1 LIKE " + "'" + segValue1 + "'" +
"AND SegValue2 LIKE " + "'" + segValue2 + "'" + "AND SegValue3 LIKE " + "'" + segValue3 + "'";
SqlCommand commandMonth = new SqlCommand(SQLCodeMonth, conn);
// Create new SqlDataReader object and read data from the command.
using (SqlDataReader reader = commandMonth.ExecuteReader())
{
while (reader.Read())
{
string cyAct = reader["BalanceAmt"].ToString();
if (cyAct == "")
{
goto APY;
//cyAct = "0.00";
}
var cyAct1 = (float)Convert.ToDouble(cyAct);
int one = Convert.ToInt32(excelWorksheet.get_Range("E" + i, "E" + i).Text);
double cyAct2 = (cyAct1 * one);
string cyAct3 = cyAct2.ToString("0.##");
excelWorksheet.get_Range("J" + i, "J" + i).Value = cyAct3;
}
}
//end filling in column
//begin filling in Act PY month column
THIS IS NOT A FULL ANSWER, there is not enough space to write this as a comment, do not mark this as an answer its a comment.
Please try to use objects (instances of classes or structs) it will make your programming more efficient and easy to maintain.
for example:
private void UseObjects()
{
List<ExcelObjects> ListOfvarsForQuery = new List<ExcelObjects>();
for (int i = 2; i < lastUsedRow + 1; i++)
{
ExcelObjects obj = new ExcelObjects();
obj.CompanyVar = ws.Cells[i, 1];
obj.FiscalYear = ws.Cells[i, 2];
obj.FiscalPeriod = ws.Cells[i, 3];
obj.segValue1 = ws.Cells[i, 4];
obj.segValue2 = ws.Cells[i, 5];
obj.segValue3 = ws.Cells[i, 6];
ListOfvarsForQuery.Add(obj);
}
string SQLCode = // use the list of ExcelObjects and write a better query.
}
}
struct ExcelObjects
{
public string CompanyVar;
public string FiscalYear;
public string FiscalPeriod;
public string segValue1;
public string segValue2;
public string segValue3;
}
Instead of looping through each row and running a SQL query for each row, I found that it is faster to outer join the table I speak of in my question with another SQL table that has the account balances on it. I'm doing all of it within memory because I've been coding for 3 weeks and I don't have time to learn how to create a temp table in SQL server yet.
Related
i would like to insert multiple data into my database. I am using for-each statement to get the data and when i insert into the database, it generates 10(just a random no. depending on the no. of data i retrieved) rows for me with one data in every row instead of all in one row. here is the for-each statement i am using.
foreach(var kiev in dict)
{
string na = kiev.Key;
if(na != "db_table_name")
{
string quer = "insert into " + HttpContext.Current.Session["tablename"].ToString() + " ( " + kiev.Key + " ) VALUES ( '" + kiev.Value + "' ) ";
SqlCommand cl = new SqlCommand(quer, con);
cl.ExecuteNonQuery();
}
}
There are better options like "SqlBulkCopy" available as already mentioned in the comments but also something like this should work:
string tablename = "";
string values = "";
string keys = "";
foreach(var kiev in dict)
{
string na = kiev.Key;
if(na != "db_table_name")
{
keys += kiev.Key + ", ";
values += "'" + kiev.Value + "', ";
}
}
keys = keys.Remove(keys.Length - 2);
values = values.Remove(values.Length - 2);
string quer = "insert into " + HttpContext.Current.Session["tablename"].ToString() + " ( " + keys + " ) VALUES ( " + values + " ) ";
SqlCommand cl = new SqlCommand(quer, con);
cl.ExecuteNonQuery();
I am not able to find what's wrong with the following code. There is a form on which the selected start date and finish date , as well as a button transition to a new form where DataGridView populated the database , it is necessary to conclusions regarding the selected date , but that he does not want to issue ORA- 00933.No "where" all is well.
void renewOtchet()
{
dgvOtchet.Rows.Clear();
OracleCommand ocm = Oracle.DBConneciton.CreateCommand();
ocm.CommandText = "select num, date_start, date_finish, " +
"trim(name_video), price_video, " +
"trim(fam_client), " +
"trim(kind_zal) from video.allData" +
"where date_start >= ('"+ date1 + "', 'DD.MM.YYYY' ) and date_finish <= ('" + date2+ "', 'DD.MM.YYYY') ";
string[] str = new string[7];
OracleDataReader ord = ocm.ExecuteReader();
while (ord.Read())
{
for (int i = 0; i < 7; i++)
{
str[i] = ord[i].ToString();
if (i == 1 || i == 2)
{
str[i] = str[i].Remove(10);
}
}
dgvOtchet.Rows.Add(str);
}
ord.Dispose();
ord.Close();
}
You can try this.
"select num, date_start, date_finish, " +
"trim(name_video), price_video, " + "trim(fam_client), " +
"trim(kind_zal) from video.allData " +
"where date_start >= TO_DATE('"+ date1 + "', 'DD.MM.YYYY' )
and date_finish <= TO_DATE('" + date2+ "','DD.MM.YYYY') ";
string[] str = new string[7];
I am trying to use iTextSharp to populate a PDF from multiple SQL queries.
To fill out part 1 of the form, the query returns 1 name, for the second part, I need to loop through my results, which is where I am having a bit of trouble.
using (var connection2 = new SqlConnection("Data Source=PUMA; Initial Catalog=CACTUS; User ID=somethinguser; Password=digital; Connection Timeout=50"))
{
using (var command2 = connection2.CreateCommand())
{
command2.CommandText = "SELECT * from MikeACATest WHERE SSN = " + SSN + "and RELATIONCODE <> '01'";
connection2.Open();
using (var reader2 = command2.ExecuteReader())
{
while (reader2.Read())
{
var dNAME = reader2.GetValue(reader2.GetOrdinal("NAME"));
var dDOB = reader2.GetValue(reader2.GetOrdinal("DOB"));
var dP2_16_ALL = reader2.GetValue(reader2.GetOrdinal("P2_16_ALL"));
var dP2_16_1 = reader2.GetValue(reader2.GetOrdinal("P2_16_1"));
var dP2_16_2 = reader2.GetValue(reader2.GetOrdinal("P2_16_2"));
var dP2_16_3 = reader2.GetValue(reader2.GetOrdinal("P2_16_3"));
var dP2_16_4 = reader2.GetValue(reader2.GetOrdinal("P2_16_4"));
var dP2_16_5 = reader2.GetValue(reader2.GetOrdinal("P2_16_5"));
var dP2_16_6 = reader2.GetValue(reader2.GetOrdinal("P2_16_6"));
var dP2_16_7 = reader2.GetValue(reader2.GetOrdinal("P2_16_7"));
var dP2_16_8 = reader2.GetValue(reader2.GetOrdinal("P2_16_8"));
var dP2_16_9 = reader2.GetValue(reader2.GetOrdinal("P2_16_9"));
var dP2_16_10 = reader2.GetValue(reader2.GetOrdinal("P2_16_10"));
var dP2_16_11 = reader2.GetValue(reader2.GetOrdinal("P2_16_11"));
var dP2_16_12 = reader2.GetValue(reader2.GetOrdinal("P2_16_12"));
for (int i = 17; i < Convert.ToInt32(3) + 17; i++)
{ //pdfFormFields declared earlier
pdfFormFields.SetField("Part[3]." + i + "a.CoveredUserName", dNAME.ToString());
pdfFormFields.SetField("Part[3]." + i + "c.CoveredUserDOB", dDOB.ToString());
pdfFormFields.SetField("Part[3]." + i + "d.cb.CoveredMonths[All]", dP2_16_ALL.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Jan]", dP2_16_1.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Feb]", dP2_16_2.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Mar]", dP2_16_3.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Apr]", dP2_16_4.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[May]", dP2_16_5.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[June]", dP2_16_6.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[July]", dP2_16_7.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Aug]", dP2_16_8.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Sept]", dP2_16_9.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Oct]", dP2_16_10.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Nov]", dP2_16_11.ToString());
pdfFormFields.SetField("Part[3]." + i + "e.cb.CoveredMonths[Dec]", dP2_16_12.ToString());
reader2.NextResult();
}
}
}
connection2.Close();
}
}
pdfStamper.FormFlattening = false;
pdfStamper.Close();
}
The problem with this code is the command query "SELECT * from MikeACATest WHERE SSN = " + SSN + "and RELATIONCODE <> '01'"; returns 3 names: Debra, Parker and Sarah.
What I need to do is get a count of how many names show up and loop through each name, populating the PDF. I know how to populate the PDF, but my issue is looping through the query.
In my for loop (which doesn't work btw), I hardcoded the number 3 and all 3 names were of the wife (http://imgur.com/f4diZk4).
got it to work
reader2.NextResult(); was causing the issue because this was meant for multiple search queries at once like select * from groupA; select....
I have gridview which is bound to the dataset and trying to insert multipleselectedrows(CheckBoxRowSelect) to my database but everytime I failed. I tried many different ways but there is no result. My codes are for insert:
int[] selectedrows = gridView1.GetSelectedRows();
for (int i = 0; i < selectedrows.Length; i++)
{
string sql = "INSERT INTO dbo.TABLE1(COL1,COL2,COL3) SELECT " + gridView1.GetRowCellValue(i, "COL4") + "," + gridView1.GetRowCellValue(i, "COL5") + ",'" + gridView1.GetRowCellValue(i, "COL6")" FROM dbo.TABLE2 WHERE COL4=" + gridView1.GetRowCellValue(i, "COL4") + " AND COL5=" + gridView1.GetRowCellValue(i, "COL5") + "";
connection(sql); // sqlconnection and sqlcommand metod
}
Your code is wrong because you read your values NOT from the selected rows.
This should work:
int[] selectedrows = gridView1.GetSelectedRows();
foreach (int i in selectedrows)
{
string sql = "INSERT INTO dbo.TABLE1(COL1,COL2,COL3) SELECT " + gridView1.GetRowCellValue(i, "COL4") + "," + gridView1.GetRowCellValue(i, "COL5") + ",'" + gridView1.GetRowCellValue(i, "COL6")" FROM dbo.TABLE2 WHERE COL4=" + gridView1.GetRowCellValue(i, "COL4") + " AND COL5=" + gridView1.GetRowCellValue(i, "COL5") + "";
connection(sql); // sqlconnection and sqlcommand metod
}
First time post as I'm a bit stuck here.
I am using this code to return some rows from a SQL Server database:
public static SqlDataReader SQLSelect(string sqlcommand, string[,] parameters, int length)
{
try
{
conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
conn.Open();
SqlDataReader reader;
SqlCommand cmd = new SqlCommand(sqlcommand, conn);
var allLength = parameters.Length;
for (int i = 0; i < parameters.Length - length; i++)
{
string paramid = parameters[i, 0];
if (paramid == "#date" || paramid == "#Date" || paramid == "#DATE")
{
string paramvalue = parameters[i, 1];
DateTime date = Convert.ToDateTime(paramvalue);
paramvalue = date.ToString("yyyy-MM-dd HH':'mm':'ss");
cmd.Parameters.Add(new SqlParameter(paramid, paramvalue));
}
else
{
string paramvalue = parameters[i, 1];
cmd.Parameters.Add(new SqlParameter(paramid, paramvalue));
}
}
cmd.CommandType = CommandType.StoredProcedure;
reader = cmd.ExecuteReader();
return reader;
}
catch
{
return null;
}
}
This function is called like so
string[,] parameters = new string[1, 2] { { "#studentid", studentid } };
SqlDataReader reader = Common.SQLSelect(Common.tblstudentprogressselectforprinting, parameters, 1);
now all runs fine except the reader only contains 13 rows of data where as the actual query being
exec sp_tblstudentprogress_selectforprinting #studentid=N'87'
as an example, returns 91 rows.
I'm at a loss as to why this is the case. Only thing I have noticed is when using SQL Server profiler, running the query from SQL Server, there is a RPC: Started and Completed, as for running from withing my web app, there is only an RPC: Started.
Any thoughts on this?
EDIT:
here is how I enumerate the reader
protected void btnPrint_Click(object sender, EventArgs e)
{
string[,] parameters = new string[1, 2] { { "#studentid", studentid } };
SqlDataReader reader = Common.SQLSelect(Common.tblstudentprogressselectforprinting, parameters, 1);
string firstname = txtFirstName.Text;
string lastname = txtLastName.Text;
int i=0;
string[] heading1 = new string[reader.FieldCount];
string[] heading2 = new string[reader.FieldCount];
string[] log = new string[reader.FieldCount];
try
{
while (reader.Read())
{
heading1[i] = "Progress Log for: Block: " + reader["block"].ToString() + " Lesson: " + reader["lesson"].ToString();
heading2[i] = "";
log[i] =
/*"PROGRESS LOG for " + reader["firstname"].ToString() + " " + reader["lastname"].ToString() + " Printed on " + DateTime.Today.ToShortDateString() + Environment.NewLine +*/
Environment.NewLine +
"Teacher: " + reader["teacher"].ToString() + Environment.NewLine +
"Date: " + reader["date"].ToString() + Environment.NewLine +
"Year: " + reader["year"].ToString() + Environment.NewLine +
"Block: " + reader["block"].ToString() + Environment.NewLine +
"Lesson: " + reader["lesson"].ToString() + Environment.NewLine +
"Warm Up: " + reader["warmup"].ToString() + Environment.NewLine +
"Range: " + reader["range"].ToString() + Environment.NewLine +
"Technique Sheet: " + reader["techniquesheet"].ToString() + Environment.NewLine +
"Technique Other: " + reader["techniqueother"].ToString() + Environment.NewLine +
Environment.NewLine +
"Notes: " + reader["notes"].ToString() + Environment.NewLine +
Environment.NewLine +
"Mark: " + reader["mark"].ToString()+ Environment.NewLine ;
i++;
}
}
catch
{
}
finally
{
if (Common.conn != null)
{
Common.conn.Close();
}
}
Common.PDFCreateProgressLog("Progress log for: " + firstname + " " + lastname, "Progress log for: " + firstname + " " + lastname, "PDF_" + firstname + " " + lastname + "-" + DateTime.Today.ToString("yyyy-MM-dd") + ".pdf", "Progress log for: " + firstname + " " + lastname, log, heading1, heading2);
}
You are confusing the meaning of the FieldCount property. It identifies the number of Columns, not the number of Rows. You cannot determine the total number of rows from a streaming source like a Reader, without enumerating all of the rows first (at least once, anyway).
So you will need to extend your arrays each time (lists might be easier for this) you read a row from the Reader and test the Reader to se when there are no more rows.