How could I speed up deleting columns in Excel? - c#

I would like to accelerate the process of deleting columns in Excel. I have 2 Excel files. Let's say data file where all data exist and the deleting column names in other file. There are many worksheets in data file some have more than 15000 columns and around 2500 rows in deleting column file. It is taking longer time to delete. My question how could I speed up the code below?
private void workerdelete_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
totalRow = xlWorksheetdelvariable.UsedRange.Rows.Count;
Excel.Range startCell = xlWorksheetdelvariable.Cells[2, 1];
Excel.Range endCell = xlWorksheetdelvariable.Cells[totalRow, 1];
Excel.Range currentRange = xlWorksheetdelvariable.get_Range(startCell, endCell).Cells;
object[,] matrixReaddelvariable = (object[,])currentRange.Value;
foreach (Excel.Worksheet sheet in xlWorkbookDelete.Sheets)
{
xlWorksheetdelete = xlWorkbookDelete.Sheets[sheet.Index];
columnCount = xlWorksheetdelete.UsedRange.Columns.Count;
int rowCount = xlWorksheetdelete.UsedRange.Rows.Count;
Excel.Range startCelldelete = xlWorksheetdelete.Cells[1, 1];
Excel.Range endCelldelete = xlWorksheetdelete.Cells[1, columnCount];
Excel.Range currentRangedelete = xlWorksheetdelete.get_Range(startCelldelete, endCelldelete).Cells;
object[,] matrixReaddelete = (object[,])currentRangedelete.Value;
List<int> delCols = new List<int>();
for (int c = 1; c <= columnCount; c++)
{
for (int r = 1; r < totalRow; r++)
{
if (dellabel == true)
{
if (matrixReaddelete[1, c].ToString() == matrixReaddelvariable[r, 1].ToString()||matrixReaddelete[1, c].ToString().Contains("_label"))
{
delCols.Insert(0, c);
break;
}
}
else if(matrixReaddelete[1, c].ToString() == matrixReaddelvariable[r, 1].ToString())
{
delCols.Insert(0, c);
break;
}
}
int percentage = (c + 1) * 50 / columnCount;
workerdelete.ReportProgress(percentage);
}
foreach (int colIndex in delCols)
{
xlWorksheetdelete.Columns[colIndex].Delete();
int percentage = 50 + ( delCols.IndexOf(colIndex) + 1 ) * 50 / delCols.Count;
workerdelete.ReportProgress(percentage);
}
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message);
}
}

Related

Create an Excel file with the Excel interop class from SQL Database

I want to create an Excel file with the Excel interop class from the SQL Database. With SQL query, I had previously transferred the dataset into dataGridview. The result of the query is the data. However, I can't Print this data from the SQL database to Excel cells with the dataset.
private void linkLabel10_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
using (var fbd = new FolderBrowserDialog())
{
DialogResult result = fbd.ShowDialog();
if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
{
string fileTest = fbd.SelectedPath.ToString() + "\\"+ comboBox1.Text.Substring(0, comboBox1.Text.IndexOf("*") - 1) +"-"+ comboBox2.Text.Substring(0, comboBox2.Text.IndexOf("(") - 1) +"-"+ comboBox2.Text.Substring(comboBox2.Text.IndexOf("(") + 1, 10) + ".xlsx";
MessageBox.Show(fileTest);
if (File.Exists(fileTest))
{
File.Delete(fileTest);
}
SqlDataAdapter da = new SqlDataAdapter("select PersonelKodu= ztSinifEgitimiDurum.KisiID, İsim= dbo.cdCurrAcc.FullName, Katılım = CASE WHEN Katilim = 1 THEN 'Katıldı' ELSE 'Katılmadı' END, ztSinifEgitimiDurum.ID FROM dbo.ztSinifEgitimiDurum INNER JOIN dbo.cdCurrAcc ON cdCurrAcc.CurrAccCode = ztSinifEgitimiDurum.KisiID AND cdCurrAcc.CurrAccTypeCode = ztSinifEgitimiDurum.KisiTipiID WHERE AtamaID =" + AtamaIDBul(), baglan);
DataSet ds = new DataSet();
Excel.Application Excel;
Excel.Worksheet excelWorkSheet;
Excel.Workbook excelWorkBook;
Excel = new Excel.Application();
excelWorkBook = Excel.Workbooks.Add();
excelWorkSheet = (Excel.Worksheet)excelWorkBook.Worksheets.get_Item(1);
excelWorkSheet.Cells[1, 1] = "some value";
excelWorkSheet.Name = "Ali";
foreach (DataTable table in ds.Tables)
{
for (int i = 1; i < table.Columns.Count + 1; i++)
{
excelWorkSheet.Cells[1, i] = table.Columns[i - 1].ColumnName;
MessageBox.Show(table.Columns[i - 1].ColumnName.ToString());
}
for (int j = 0; j < table.Rows.Count; j++)
{
for (int k = 0; k < table.Columns.Count; k++)
{
excelWorkSheet.Cells[j + 2, k + 1] = table.Rows[j].ItemArray[k].ToString();
}
}
}
// excelWorkSheet.Cells[1, 1] = "some value";
excelWorkBook.SaveAs(fileTest);
excelWorkBook.Close();
Excel.Quit();
}
}
}
You forgot to fill your DataSet, add this line
da.Fill(ds); after DataSet ds = new DataSet();
You can try this code to fill your sheet with values from a table:
ws.Activate();
foreach (DataTable dt in ds.Tables)
{
// Add column headers from the datatable
for (int Idx = 0; Idx < dt.Columns.Count; Idx++)
{
ws.Range["A1"].Offset[0, Idx].Value = dt.Columns[Idx].ColumnName;
}
// add data rows
for (int Idx = 0; Idx < dt.Rows.Count; Idx++)
{ // hey I did not invent this line of code, I found it somewhere on CodeProject.
// It works to add the whole row at once
ws.Range["A2"].Offset[Idx].Resize[1, dt.Columns.Count].Value = dt.Rows[Idx].ItemArray;
}
...
But you will have to add more worksheets for individual tables in case there is more than one table in your DataSet.
It is based on this article.

How to Check for Empty data entry before populating ListBox

private void LoadExcelSheet(string path, int sheet){
_Application excel = new Excel.Application();
Workbook wb;
Worksheet ws;
string data = "";
int row = 0;
int col = 0;
wb = excel.Workbooks.Open(path);
ws = wb.Worksheets[sheet];
listBox1.Items.Clear();
for (row = 1; row < 10; row++){
data = " ";
for (col = 1; col < 3; col++) {
data += ws.Cells[row, col].Value2 + " ";
}
//wanted to filter out empty cells/data and at the same time count
//number of items in the list... row should stop.. I think!
if(data == null){
break;
}
listBox1.Items.Add(data);
}
The if statement doesn't seems to work no matter what I do. I would appreciate it very if anyone could point me in the right direction.
use it like this:
if (data.Trim().Length < 1)
{
return;
}
use return not break
Add a condition like this
If(string.IsNullOrEmpty(data))
{
Break;
}

SSIS Export to Excel using Script Task

I'm trying to use a Script Task to export data to Excel because some of the reports I generate simply have too many columns to keep using a template file.
The most annoying part about using a template is: if something as simple as a column header changes, the metadata gets screwed forcing me to recreate my DataFlow. Because I use an OLE DB source, I need to use a Data Transformation task to convert between unicode and non-unicode character sets, then remap my Excel Destination to the "Copy of field x" in order for the Excel document to create properly.
This takes far too long and I need a new approach.
I have the following method in a script task using Excel = Microsoft.Office.Interop.Excel:
private void ExportToExcel(DataTable dataTable, string excelFilePath = null)
{
Excel.Application excelApp = new Excel.Application();
Excel.Worksheet workSheet = null;
try
{
if (dataTable == null || dataTable.Columns.Count == 0)
throw new System.Exception("Null or empty input table!" + Environment.NewLine);
excelApp.Workbooks.Add();
workSheet = excelApp.ActiveSheet;
for (int i = 0; i < dataTable.Columns.Count; i++)
{
workSheet.Cells[1, (i + 1)] = dataTable.Columns[i].ColumnName;
}
foreach (DataTable dt in dataSet.Tables)
{
// Copy the DataTable to an object array
object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];
// Copy the column names to the first row of the object array
for (int col = 0; col < dt.Columns.Count; col++)
{
rawData[0, col] = dt.Columns[col].ColumnName;
}
// Copy the values to the object array
for (int col = 0; col < dt.Columns.Count; col++)
{
for (int row = 0; row < dt.Rows.Count; row++)
{
rawData[row + 1, col] = dt.Rows[row].ItemArray[col];
}
}
// Calculate the final column letter
string finalColLetter = string.Empty;
string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int colCharsetLen = colCharset.Length;
if (dt.Columns.Count > colCharsetLen)
{
finalColLetter = colCharset.Substring((dt.Columns.Count - 1) / colCharsetLen - 1, 1);
}
finalColLetter += colCharset.Substring((dt.Columns.Count - 1) % colCharsetLen, 1);
workSheet.Name = dt.TableName;
// Fast data export to Excel
string excelRange = string.Format("A1:{0}{1}", finalColLetter, dt.Rows.Count + 1);
//The code crashes here (ONLY in SSIS):
workSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;
// Mark the first row as BOLD
((Excel.Range)workSheet.Rows[1, Type.Missing]).Font.Bold = true;
}
List<int> lstColumnsToSum = new List<int>() { 9 };
Dictionary<int, string> dictColSumName = new Dictionary<int, string>() { { 9, "" } };
Dictionary<int, decimal> dictColumnSummation = new Dictionary<int, decimal>() { { 9, 0 } };
// rows
for (int i = 0; i < dataTable.Rows.Count; i++)
{
for (int j = 1; j <= dataTable.Columns.Count; j++)
{
workSheet.Cells[(i + 2), (j)] = dataTable.Rows[i][j - 1];
if (lstColumnsToSum.Exists(x => (x == j)))
{
decimal val = 0;
if (decimal.TryParse(dataTable.Rows[i][j - 1].ToString(), out val))
{
dictColumnSummation[j] += val;
}
}
}
}
//Footer
int footerRowIdx = 2 + dataTable.Rows.Count;
foreach (var summablecolumn in dictColSumName)
{
workSheet.Cells[footerRowIdx, summablecolumn.Key] = String.Format("{0}", dictColumnSummation[summablecolumn.Key]);
}
// check fielpath
if (excelFilePath != null && excelFilePath != "")
{
try
{
if (File.Exists(excelFilePath))
File.Delete(excelFilePath);
workSheet.Activate();
workSheet.Application.ActiveWindow.SplitRow = 1;
workSheet.Application.ActiveWindow.FreezePanes = true;
int row = 1;
int column = 1;
foreach (var item in dataTable.Columns)
{
Excel.Range range = workSheet.Cells[row, column] as Excel.Range;
range.NumberFormat = "#";
range.EntireColumn.AutoFit();
range.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
column++;
}
Excel.Range InternalCalculatedAmount = workSheet.Cells[1, 9] as Excel.Range;
InternalCalculatedAmount.EntireColumn.NumberFormat = "#0.00";
InternalCalculatedAmount.Columns.AutoFit();
workSheet.SaveAs(excelFilePath);
}
catch (System.Exception ex)
{
throw new System.Exception("Excel file could not be saved! Check filepath." + Environment.NewLine + ex.Message);
}
}
else // no filepath is given
{
excelApp.Visible = true;
}
}
catch (System.Exception ex)
{
throw new System.Exception("ex.Message + Environment.NewLine, ex.InnerException);
}
}
The exception thrown is a System.OutOfMemoryException when trying to execute the following piece of code:
workSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;
My biggest frustration is that this method works 100% in a regular C# application.
The DataTable contains about 435000 rows. I know it's quite a bit of data but I use this very method, modified of course, to split data across multiple Excel worksheets in one of my other applications, and that DataSet contains about 1.1m rows. So less than half of my largest DataSet should be a walk-in-the-park...
Any light shed on this matter would be amazing!

Export Sql data to Excel , Store long int to string in excel

I have this working C# code to export Sql Server data to excel. The problem is one column contains long int and it appears in excel as 6.71524E+11. So I understand that we have to convert it as string in excel.
How to implement that in my code? Examples would be appreciated.
public static void ExportToExcel(DataTable dt)
{
try
{
string conString = "Data Source=DELL\\SQLSERVER1;Trusted_Connection=True;DATABASE=Camo;CONNECTION RESET=FALSE";
SqlConnection sqlCon = new SqlConnection(conString);
sqlCon.Open();
SqlDataAdapter da = new SqlDataAdapter("select TOP 10000 LocalSKU,ItemName, QOH,Price,Discontinued,Barcode,Integer2,Integer3,SalePrice,SaleOn,Price2 from dbo.Inventory", sqlCon);
System.Data.DataTable dtMainSQLData = new System.Data.DataTable();
da.Fill(dtMainSQLData);
DataColumnCollection dcCollection = dtMainSQLData.Columns;
// Export Data into EXCEL Sheet
Microsoft.Office.Interop.Excel.ApplicationClass ExcelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();
ExcelApp.Application.Workbooks.Add(Type.Missing);
int i = 1;
int j = 1;
//header row
foreach (DataColumn col in dtMainSQLData.Columns)
{
ExcelApp.Cells[i, j] = col.ColumnName;
j++;
}
i++;
//data rows
foreach (DataRow row in dtMainSQLData.Rows)
{
for (int k = 1; k < dtMainSQLData.Columns.Count + 1; k++)
{
ExcelApp.Cells[i, k] = row[k - 1].ToString();
}
i++;
}
ExcelApp.ActiveWorkbook.SaveCopyAs("C:/Users/Administrator.CAMO/Downloads/FtpFilesStorage/Export/Sheet1.xlsx");
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
Console.WriteLine(".xlsx file Exported succssessfully.");
}
This method work for exporting to an Excel file.
private void ExportToExcel(DataTable Tbl, string ExcelFilePath = null)
{
try
{
if (Tbl == null || Tbl.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
Excel.Application excelApp = new Excel.Application();
//Excel.Workbook ExcelBookServices = excelApp.Workbooks.Add();
excelApp.Workbooks.Add();
// single worksheet
Excel._Worksheet workSheet = (Excel._Worksheet)excelApp.ActiveSheet;
// column headings
for (int i = 0; i < Tbl.Columns.Count; i++)
{
workSheet.Cells[1, (i + 1)] = Tbl.Columns[i].ColumnName;
}
// rows
for (int i = 0; i < Tbl.Rows.Count; i++)
{
// to do: format datetime values before printing
for (int j = 0; j < Tbl.Columns.Count; j++)
{
workSheet.Cells[(i + 2), (j + 1)] = Tbl.Rows[i][j];
}
}
workSheet.Columns.AutoFit();
//workSheet.Columns.Style = "Output";
//Excel.Range cell = ((Excel.Range)workSheet.Cells[Tbl.Rows.Count, Tbl.Columns.Count]);
// check fielpath
if (ExcelFilePath != null && ExcelFilePath != "")
{
try
{
workSheet.SaveAs(ExcelFilePath);
excelApp.Quit();
//File Saved Message
}
catch (Exception ex)
{
//ExportToExcel: Excel file could not be saved! Check filepath Message
}
}
else // no filepath is given
{
excelApp.Visible = true;
}
}
catch (Exception ex)
{
//Error in creating the Excel file
ScriptManager.RegisterStartupScript(this, GetType(), "Message", "ExportToExcel: \n" + ex.Message, true);
}
}
Change the for loop to
int i = 1;
int j = 1;
//header row
foreach (DataColumn col in dtMainSQLData.Columns)
{
ExcelApp.Cells[i, j] = col.ColumnName;
j++;
ExcelApp.Rows.AutoFit();
ExcelApp.Columns.AutoFit();
}
i++;
Console.Write("Progressing......65% \n Wait for around 8 minutes \r");
//data rows
foreach (DataRow row in dtMainSQLData.Rows)
{
for (int k = 1; k < dtMainSQLData.Columns.Count + 1; k++)
{
ExcelApp.Cells[i, k] = "'" + row[k - 1].ToString();
}
i++;
ExcelApp.Columns.AutoFit();
ExcelApp.Rows.AutoFit();
}
use the property NumberFormat:
MyWorkBook.NumberFormat = "#";

How can I insert a new row in excel after a specific value written vertically on merged cells in column A, using C#?

So I have an excel file with multiple columns and rows, and column A is divided into 4 categories. Category one witch spreads over 3 merged rows vertically, category 2 witch spreads over 54 rows vertically and so on. The name of the category is also written vertically. I also have a form with a comboBox from witch I can select one of those categories and using that selection I want to compare it to the category from excel and be able to insert a new row at the end of that specific category.
Figured out the solution and it's something like this:
public static void WriteToExcelFolderAccess(Employee empl)
{
try
{
string[] cellVal = new string[lastRowFold];
for (int k = 1; k <= lastRowFold; k++)
{
string str = mySheetFold.UsedRange.Cells[k, 1].Text;
cellVal[k - 1] = str;
}
var temp = new List<string>();
foreach (string val in cellVal)
{
if (!string.IsNullOrEmpty(val))
temp.Add(val);
}
cellVal = temp.ToArray();
for (int i = 3; i <= lastRowFold; i++)
{
if (mySheetFold.Cells[i, 1].Text == cellVal[empl.CompanyIndex].ToString())
{
MessageBox.Show("found it");
int found = i;
empl.CompanyIndex += 1;
for (int j = i; j <= lastRowFold; j++)
{
if (empl.CompanyIndex < cellVal.Length)
{
if (mySheetFold.Cells[j, 1].Text == cellVal[empl.CompanyIndex].ToString())
{
MessageBox.Show("insert row above");
excel.Range rng = mySheetFold.Cells[j, 1];
excel.Range row = rng.EntireRow;
row.Insert(excel.XlInsertShiftDirection.xlShiftDown, System.Type.Missing);
mySheetFold.Range[mySheetFold.Cells[found, 1], mySheetFold.Cells[j, 1]].Merge();
break;
}
}
else
{
MessageBox.Show("insert row below");
excel.Range rng = mySheetFold.Cells[j, 1];
excel.Range row = rng.EntireRow;
row.Insert(excel.XlInsertShiftDirection.xlShiftDown, System.Type.Missing);
mySheetFold.Range[mySheetFold.Cells[found, 1], mySheetFold.Cells[j+1, 1]].Merge();
break;
}
}
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
folderAccessList.Save();
folderAccessList.Close();
}
}
The MessageBox()'es used are just for testing purposes.
My problem now is how can I insert a row after the last row of data therefor keeping the cell's formatting. The following piece of code is the one that needs modifying in order to insert bellow.
else
{
MessageBox.Show("insert row below");
excel.Range rng = mySheetFold.Cells[j, 1];
excel.Range row = rng.EntireRow;
row.Insert(excel.XlInsertShiftDirection.xlShiftDown, System.Type.Missing);
mySheetFold.Range[mySheetFold.Cells[found, 1], mySheetFold.Cells[j+1, 1]].Merge();
break;
}

Categories