Reputation: 1
I run a stored procedure that I want to dump on an Excel template.
It currently works, but just takes way too long. In SQL Server Management Studio, the query runs fine, but when I am just writing to the template it is really slow.
Can anyone suggest a more efficient way to achieve the same result?
Here is part of my code:
sdate = StartDate.Value.ToString();
edate = EndDate.Value.ToString();
Excel.Application oXL;
Excel._Workbook oWB;
Excel._Worksheet aSheet;
try
{
//Start Excel and get Application object.
oXL = new Excel.Application();
oXL.Visible = true;
//open the excel template
oWB = oXL.Workbooks.Open("C:\\TEMP\\template.xlsm");
//oWB = (Excel._Workbook)(oXL.Workbooks.Add(Missing.Value));
//Call to service
//aSheet = (Excel._Worksheet)oWB.Worksheets.get_Item(1);
aSheet = (Excel._Worksheet)oWB.ActiveSheet;
//backgroundWorker1.ReportProgress(i++);
writedata_from_proc(aSheet, "dbo.CODE_RED_2017");
//backgroundWorker1.ReportProgress(i++);
//Make sure Excel is visible and give the user control
//of Microsoft Excel's lifetime.
//backgroundWorker1.ReportProgress(i++);
MessageBox.Show("Data extraction complete");
oXL.Visible = true;
oXL.UserControl = true;
//SaveExcel(oWB);
//clean up the COM objects to remove them from the memory
Marshal.FinalReleaseComObject(aSheet);
Marshal.FinalReleaseComObject(oWB);
Marshal.FinalReleaseComObject(oXL);
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);
MessageBox.Show(errorMessage, "Error");
}
}
Here is the code I initially missed:
public void writedata_from_proc(Excel._Worksheet oWS,string sentproc)
{
int rowCount = 0;
SqlCommand cmd = new SqlCommand(sentproc.ToString());
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@start_date", SqlDbType.DateTime).Value = getsdate();
cmd.Parameters.Add("@end_date",SqlDbType.DateTime).Value=getedate();
cmd.CommandTimeout = 0;
DataTable dt = GetData(cmd);
oWS.UsedRange.Rows.Count.ToString();
if (sentproc.Contains("CODE_RED"))
{
rowCount = 1;
}
else
{
rowCount = oWS.UsedRange.Rows.Count;
}
foreach (DataRow dr in dt.Rows)
{
rowCount += 1;
for (int i = 1; i < dt.Columns.Count + 1; i++)
{
// Add the header the first time through
if (rowCount == 2)
{
oWS.Cells[1, i] = dt.Columns[i - 1].ColumnName;
}
oWS.Cells[rowCount, i] = dr[i - 1];
}
}
}
Upvotes: 0
Views: 310
Reputation: 16377
Excel already has a built in tool that does exactly this, and it takes no longer than it would to run the query and fetch the results. It's called MS Query. In a nutshell, you would:
exec dbo.CODE_RED_2017
Best of all, when it's time to refresh, you right-click on the table and select "Refresh" and it will re-execute your procedure (or query). In my experience, Excel actually renders the data faster than most database browsers.
Here's a Microsoft link with more details:
So, you don't need C# at all. That said, if you're automating this somehow through C#, this can also be done that way as well. Here is an example:
string sql = "exec dbo.CODE_RED_2017";
string source = "your connection string here";
Excel.Range r = activeSheet.Range["A1"];
Excel.ListObject lo = sheet.ListObjects.AddEx(Excel.XlListObjectSourceType.xlSrcQuery,
source, true, Excel.XlYesNoGuess.xlGuess, r);
lo.QueryTable.CommandText = sql;
lo.Refresh();
Upvotes: 1