Excel to DataGrid Exponential Issue - c#

I'm using the following code to display an excel file in a data grid, the problem is, large numbers are being displayed as exponential form i.e. 1236548965132160 is displayed as 1.23654896513216E+15 in the grid,
string xlsxString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=myFile.xlsx;Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\"";
OleDbConnection excelOleDBConnection = new OleDbConnection(xlsxString);
excelOleDBConnection.Open();
OleDbDataAdapter dataAdapterForExcelFile = new OleDbDataAdapter("SELECT * FROM [Sheet1$]", excelOleDBConnection);
DataTable dataTableForTheAdapter = new DataTable();
dataAdapterForExcelFile.Fill(dataTableForTheAdapter);
this.dataGridView1.DataSource = dataTableForTheAdapter.DefaultView;
I need to remove this exponential form from the code, and not the excel, please suggest.

Two options:
DataTable dataTableForTheAdapter = new DataTable();
dataAdapterForExcelFile.FillSchema(dataTableForTheAdapter, SchemaType.Source);
for(int i = 0; i < dataTableForTheAdapter.Columns.Count; i++)
if (dataTableForTheAdapter.Columns[i].DataType == typeof(double))
dataTableForTheAdapter.Columns[i].DataType = typeof(decimal);
dataAdapterForExcelFile.Fill(dataTableForTheAdapter);
or:
this.dataGridView1.DataSource = dataTableForTheAdapter.DefaultView;
for (int i = 0; i < this.dataGridView1.Columns.Count; i++)
{
if (this.dataGridView1.Columns[i].ValueType == typeof(double))
this.dataGridView1.Columns[i].DefaultCellStyle.Format = "N";
}

Related

Populate SQL Server data in Excel (2010) spreadsheet

I'm trying to populate the data extracted from SQL Server into Excel 2010. The code below works fine, but the difficulty is that I don't create an Excel spreadsheet programmatically, it is aleady exists and I make a request for data via plugin in Excel written in C#.
Even though I set the cursor to A10 cell, Excel starts filling-out the data from the very first cell and overwrites the header (that is already exists). Please help to fix.
Code:
OdbcConnection cnn;
cnn = new OdbcConnection(azureConn);
using (OdbcCommand command = cnn.CreateCommand())
{
command.CommandText = "{call sp_Get_Excel_Data(?,?,?,?,?,?,?,?)}";
command.Parameters.AddWithValue("#StartDate", startDate);
command.Parameters.AddWithValue("#EndDate", endDate);
command.Parameters.AddWithValue("#startTime", startTime);
command.Parameters.AddWithValue("#endTime", endTime);
command.Parameters.AddWithValue("#smp", smp);
command.Parameters.AddWithValue("#Reg", reg);
command.Parameters.AddWithValue("#event", events);
command.Parameters.AddWithValue("#userId", userId);
cnn.Open();
//DataTable
OdbcDataAdapter adapter = new OdbcDataAdapter(command);
//DataSet
DataSet ds = new DataSet();
adapter.Fill(ds);
//Cast to DataTable
DataTable dataTable = ds.Tables[0];
string[] colNames = new string[dataTable.Columns.Count];
int col = 0;
foreach (DataColumn dc in dataTable.Columns)
colNames[col++] = dc.ColumnName;
w = this.Application.ActiveWorkbook;
ws = (Worksheet)w.ActiveSheet;
Range hdrRow = (Range)ws.Rows[9];
hdrRow.Value = colNames;
hdrRow.Font.Bold = true;
hdrRow.VerticalAlignment = XlVAlign.xlVAlignCenter;
//Position the cursor
var range = ws.get_Range("A10");
range.Select();
//Inserting the Column and Values into Excel file
string data = null;
int i = 0;
int j = 0;
for (i = 0; i <= dataTable.Rows.Count - 1; i++)
{
for (j = 0; j <= dataTable.Columns.Count - 1; j++)
{
data = dataTable.Rows[i].ItemArray[j].ToString();
ws.Cells[i + 2, j + 1] = data;
}
}
Hate to answer my own questions, but here is the solution (with optimized performance):
int column = 1;
foreach (DataColumn c in dataTable.Columns)
{
//Ninth row, starting from the first cell
ws.Cells[10, column] = c.ColumnName;
column++;
}
// Create a 2D array with the data from the data table
int i = 0;
string[,] data = new string[dataTable.Rows.Count, dataTable.Columns.Count];
foreach (DataRow row in dataTable.Rows)
{
int j = 0;
foreach (DataColumn c in dataTable.Columns)
{
data[i, j] = row[c].ToString();
j++;
}
i++;
}
// Set the range value to the 2D array in Excel (10th row, starting from 1st cell)
ws.Range[ws.Cells[11, 1], ws.Cells[dataTable.Rows.Count + 11, dataTable.Columns.Count]].Value = data;

Exporting datasets into multiple excel sheets of one excel file

I need to export two dataset's values in two excel sheets of the same workbook.
My Query is like:
//Dataset One:
DataSet ds1 = new DataSet();
SqlCommand commandOpen = new SqlCommand("storedproc1", conSql);
commandOpen.CommandType = CommandType.StoredProcedure;
var adaptOpen = new SqlDataAdapter();
adaptOpen.SelectCommand = commandOpen;
adaptOpen.Fill(ds1, "table");
//Dataset Two:
DataSet ds2 = new DataSet();
SqlCommand commandOpen = new SqlCommand("storedproc2", conSql);
commandOpen.CommandType = CommandType.StoredProcedure;
var adaptOpen = new SqlDataAdapter();
adaptOpen.SelectCommand = commandOpen;
adaptOpen.Fill(ds2, "table");
Now to create one Excel workbook I have used:
ExcelLibrary.DataSetHelper.CreateWorkbook("C:/New Folder/file1.xls", ds1);
But instead of this, in the same workbook I want to add two sheets; one for ds1 and another for ds2. How to do that?
Thanks.
Possible duplicate of: how to add dataset to worksheet using Excellibrary
In the answer to that question it is shown how to export a dataset to an excel file, but each table in dataset will have it's own sheet. You can modify the code for your needs.
Code from the other post:
public static void CreateWorkbook(String filePath, DataSet dataset)
{
if (dataset.Tables.Count == 0)
throw new ArgumentException("DataSet needs to have at least one DataTable", "dataset");
Workbook workbook = new Workbook();
foreach (DataTable dt in dataset.Tables)
{
Worksheet worksheet = new Worksheet(dt.TableName);
for (int i = 0; i < dt.Columns.Count; i++)
{
// Add column header
worksheet.Cells[0, i] = new Cell(dt.Columns[i].ColumnName);
// Populate row data
for (int j = 0; j < dt.Rows.Count; j++)
worksheet.Cells[j + 1, i] = new Cell(dt.Rows[j][i]);
}
workbook.Worksheets.Add(worksheet);
}
workbook.Save(filePath);
}
Export DataSet to Excel With Multiple Sheets, you can use the following codes.
First, you have to install "ClosedXML" NuGet Package in your application.
public DataSet GetDataSetExportToExcel()
{
DataSet ds = new DataSet();
var SPNames = new List<string>() { "storedproc1", "storedproc2" };
foreach (var SPName in SPNames)
{
DataTable dt = new DataTable();
dt = GetDataTableExportToExcel(SPName);
ds.Tables.Add(dt);
}
return ds;
}
private DataTable GetDataTableExportToExcel(string SPName)
{
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand(SPName, con))
{
using (var sda = new SqlDataAdapter(cmd))
{
cmd.CommandType = CommandType.StoredProcedure;
sda.Fill(dt);
return dt;
}
}
}
}
Click on Export button use following code
/// <summary>
/// Export button click event
/// </summary>
/// <returns>Return the excel file with multiple sheets</returns>
public ActionResult ExportToExcel()
{
var sheetNames = new List<string>() { "sheetName1", "sheetName2" };
string fileName = "Example.xlsx";
DataSet ds = GetDataSetExportToExcel();
XLWorkbook wbook = new XLWorkbook();
for (int k = 0; k < ds.Tables.Count; k++)
{
DataTable dt = ds.Tables[k];
IXLWorksheet Sheet = wbook.Worksheets.Add(sheetNames[k]);
for (int i = 0; i < dt.Columns.Count; i++)
{
Sheet.Cell(1, (i + 1)).Value = dt.Columns[i].ColumnName;
}
for (int i = 0; i < dt.Rows.Count; i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
Sheet.Cell((i + 2), (j + 1)).Value = dt.Rows[i][j].ToString();
}
}
}
Stream spreadsheetStream = new MemoryStream();
wbook.SaveAs(spreadsheetStream);
spreadsheetStream.Position = 0;
return new FileStreamResult(spreadsheetStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = fileName };
}
I hope it will work.
Here we can export several tables into single excel sheet.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using Excel = Microsoft.Office.Interop.Excel;
namespace multiplesheets_export
{
class Program
{
public static void Main(string[] args)
{
object missing = Type.Missing;
SqlConnection con = new SqlConnection("Data Source=WINCTRL-KJ8RKFO;Initial Catalog=excel;Integrated Security=True");
SqlDataAdapter da = new SqlDataAdapter("select * from Employee", con);
SqlDataAdapter da1 = new SqlDataAdapter("select * from Department", con);
DataTable dt = new DataTable();
DataTable dt1 = new DataTable();
da.Fill(dt);
da1.Fill(dt1);
if (dt == null || dt.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
Excel.Application oXL = new Excel.Application();
Excel.Workbook oWB = oXL.Workbooks.Add(missing);
Excel.Worksheet oSheet = oWB.ActiveSheet as Excel.Worksheet;
oSheet.Name = "Employee Details";
for (var i = 0; i < dt.Columns.Count; i++)
{
oSheet.Cells[1, i + 1] = dt.Columns[i].ColumnName;
}
for (var i = 0; i < dt.Rows.Count; i++)
{
for (var j = 0; j < dt.Columns.Count; j++)
{
oSheet.Cells[i + 2, j + 1] = dt.Rows[i][j];
}
}
// From Here am taking EXCEL SHEET -2
Excel.Worksheet oSheet2 = oWB.Sheets.Add(missing, missing, 1, missing)as Excel.Worksheet;
if (dt1 == null || dt1.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
oSheet2.Name = "Depatment Details";
for (var i = 0; i < dt1.Columns.Count; i++)
{
oSheet2.Cells[1, i + 1] = dt1.Columns[i].ColumnName;
}
for (var i = 0; i < dt1.Rows.Count; i++)
{
for (var j = 0; j < dt1.Columns.Count; j++)
{
oSheet2.Cells[i + 2, j + 1] = dt1.Rows[i][j];
}
}
oXL.Visible = true;
}
}
}
To put data into excel sheets, you don't need to bring the data into datasets. You can directly pull the data onto excel sheet in many ways. One of this ways is to use QueryTables.Add method. With this approach, when data is modified on source, change is reflected in the excel file. ie: (using sample Northwind data):
void Main()
{
Microsoft.Office.Interop.Excel.Application xl = new Microsoft.Office.Interop.Excel.Application();
var workbook = xl.Workbooks.Add();
Worksheet sht1, sht2;
sht1 = ((Worksheet)workbook.Sheets[1]);
if (workbook.Sheets.Count < 2)
{
sht2 = (Worksheet)workbook.Sheets.Add();
}
else
{
sht2 = ((Worksheet)workbook.Sheets[2]);
}
xl.Visible = true;
sht1.Move(sht2);
sht1.Name = "Data Sheet 1";
sht2.Name = "Data Sheet 2";
string strCon = #"OLEDB;Provider=SQLNCLI11.0;server=.\SQLExpress;Trusted_Connection=yes;Database=Northwind";
Range target1 = (Range)sht1.Range["A1"];
sht1.QueryTables.Add(strCon, target1, "Select * from Customers" ).Refresh();
Range target2 = (Range)sht2.Range["A1"];
sht2.QueryTables.Add(strCon, target2, "Select * from Orders").Refresh();
}
Another option is to use the Epplus library from Nuget. Using that one you can simply have many sheets where you load the content from collections. ie:
void Main()
{
ExcelPackage pck = new ExcelPackage();
var collection1 = from c in db.Customers
select new
{
CustomerName = c.CompanyName,
ContactPerson = c.ContactName,
FirstOrder = c.Orders.Min(o => o.OrderDate),
LastOrder = c.Orders.Max(o => o.OrderDate),
OrderTotal = c.Orders.Any() ? c.Orders.Sum(o => o.OrderDetails.Sum(od => od.Quantity * od.UnitPrice)) : 0M,
Orders = c.Orders.Count()
};
var collection2 = db.Orders.Select(o => new {
OrderId = o.OrderID, Customer=o.CustomerID, OrderDate=o.OrderDate});
var ws1 = pck.Workbook.Worksheets.Add("My Sheet 1");
//Load the collection1 starting from cell A1 in ws1
ws1.Cells["A1"].LoadFromCollection(collection1, true, TableStyles.Medium9);
ws1.Cells[2, 3, collection1.Count() + 1, 3].Style.Numberformat.Format = "MMM dd, yyyy";
ws1.Cells[2, 4, collection1.Count() + 1, 4].Style.Numberformat.Format = "MMM dd, yyyy";
ws1.Cells[2, 5, collection1.Count() + 1, 5].Style.Numberformat.Format = "$#,##0.0000";
ws1.Cells[ws1.Dimension.Address].AutoFitColumns();
var ws2 = pck.Workbook.Worksheets.Add("My Sheet 2");
//Load the collection1 starting from cell A1 in ws1
ws2.Cells["A1"].LoadFromCollection(collection2, true, TableStyles.Medium9);
//...and save
var fi = new FileInfo(#"d:\temp\AnonymousCollection.xlsx");
if (fi.Exists)
{
fi.Delete();
}
pck.SaveAs(fi);
}
PS: Both QueryTables and Epplus approaches are fast. If you would anyway use datasets and\or setting cell values in a loop, then be sure you have small data.

Faster way of storing Excel worksheet to system.data.datatable using C#

I am trying to find a faster way to read an XML file that can be opened in Excel 2010. I cannot immediately read the XML file using readxml method because it contains Workbook, style, cell, data and other tags. So my approach was to open it in Excel then get the data on sheet 2 only. The sample file contains 9,000+ rows and takes about 2mins 49secs to store in a datatable. The actual file has 25,000+ rows. This is what I have tried:
private void bulkInsert()
{
var s = new Stopwatch();
s.Start();
try
{
KillExcel();
GCollector();
Excel.Application app = null;
app = new Excel.Application();
Excel.Worksheet sheet = null;
Excel.Workbook book = null;
book = app.Workbooks.Open(#"my directory for the file");
sheet = (Worksheet)book.Sheets[2];
sheet.Select(Type.Missing);
var xlRange = (Excel.Range)sheet.Cells[sheet.Rows.Count, 1];
int lastRow = (int)xlRange.get_End(Excel.XlDirection.xlUp).Row;
int newRow = lastRow + 1;
var cellrow = newRow;
int columns = sheet.UsedRange.Columns.Count;
Excel.Range test = sheet.UsedRange;
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Node_SegmentName");
dt.Columns.Add("Type");
dt.Columns.Add("Sub-Type");
dt.Columns.Add("Description");
dt.Columns.Add("Parameter_DataIdentifier");
dt.Columns.Add("RuntimeValue");
dt.Columns.Add("Category");
dt.Columns.Add("Result");
dt.TableName = "SsmXmlTable";
//slow part
for (i = 0; i < lastRow; i++)
{
DataRow excelRow = dt.NewRow();
for (int j = 0; j < columns; j++)
{
excelRow[j] = test.Cells[i + 2, j + 1].Value2;
}
dt.Rows.Add(excelRow);
}
dataGridView1.DataSource = dt;
DataSet ds = new DataSet();
ds.Tables.Add(dt);
ds.WriteXml(AppDomain.CurrentDomain.BaseDirectory + String.Format("\\XMLParserOutput{0}.xml", DateTime.Now.ToString("MM-d-yyyy")));
DataSet reportData = new DataSet();
reportData.ReadXml(AppDomain.CurrentDomain.BaseDirectory + String.Format("\\XMLParserOutput{0}.xml", DateTime.Now.ToString("MM-d-yyyy")));
SqlConnection connection = new SqlConnection("Data Source=YOURCOMPUTERNAME\\SQLEXPRESS;Initial Catalog=YOURDATABASE;Integrated Security=True;Connect Timeout=0");
connection.Open();
SqlBulkCopy sbc = new SqlBulkCopy(connection);
sbc.DestinationTableName = "Test";
sbc.WriteToServer(reportData.Tables["SsmXmlTable"]);
connection.Close();
s.Stop();
var duration = s.Elapsed;
MessageBox.Show(duration.ToString() + " bulk insert way");
MessageBox.Show(ds.Tables["SsmXmlTable"].Rows.Count.ToString());//439 rows
}
catch (Exception ex)
{
KillExcel();
GCollector();
MessageBox.Show(ex.ToString() + i.ToString());
}
}
Without the reading from Excel part, the insertion of data using bulk copy only takes a couple of seconds (0.5secs for 449 rows).
For others who are encountering the same issue, what I did was:
save the xml as an xlsx file
use oledb to read the xlsx file
store in dataset using OleDbAdapter (Fill() method)
bulk insert
Here is the code that I used to do this (change the connection string):
Stopwatch s = new Stopwatch();
s.Start();
string sSheetName = null;
string sConnection = null;
System.Data.DataTable sheetData = new System.Data.DataTable();
System.Data.DataTable dtTablesList = default(System.Data.DataTable);
OleDbConnection oleExcelConnection = default(OleDbConnection);
sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + #"C:\Users\YOURUSERNAME\Documents\Visual Studio 2012\Projects\TestXmlParser\TestXmlParser\bin\Debug\ConsolidatedSSMFiles.xlsx" + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"";
oleExcelConnection = new OleDbConnection(sConnection);
oleExcelConnection.Open();
dtTablesList = oleExcelConnection.GetSchema("Tables");
if (dtTablesList.Rows.Count > 0)
{
sSheetName = dtTablesList.Rows[0]["TABLE_NAME"].ToString();
}
dtTablesList.Clear();
dtTablesList.Dispose();
if (!string.IsNullOrEmpty(sSheetName))
{
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [TEST$]", oleExcelConnection);
sheetAdapter.Fill(sheetData);
} s.Stop();
var duration = s.Elapsed;
oleExcelConnection.Close();
dataGridView1.DataSource = sheetData;
MessageBox.Show(sheetData.Rows.Count.ToString()+"rows - "+ duration.ToString());
This reads 25000+ rows of excel data to a datable in approx. 1.9 to 2.0 seconds.

Excel Sheets into multiple C# datatables

I am trying to import a excel spreadsheet into a an array of datatables. Each table will be a sheet from the spreadsheet. Right now I am seeing that each table contains the information from all sheets. I am thinking this part is not working correctly.
dataSet.Clear();
Let me know if you can see what I am doing wrong.
Here is the rest of the code.
public DataTable[] ReadDoc()
{
string filename = #"C:\Documents and Settings\user\Desktop\Test.xlsx";
DataTable dt = null;
string connectionString = String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES\";", filename);
OleDbConnection connection = new OleDbConnection(connectionString);
DataSet dataSet = new DataSet();
DataSet finalDataSet = new DataSet();
DataTable[] table = new DataTable[3];
connection.Open();
dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
String[] excelSheets = new String[dt.Rows.Count];
int i = 0;
foreach (DataRow row in dt.Rows)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
i++;
}
// Loop through all of the sheets if you want too...
for (int j = 0; j < excelSheets.Length; j++)
{
string query = String.Format("SELECT * FROM [" + excelSheets[j] + "]");
dataSet.Clear();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(query, connectionString);
dataAdapter.Fill(dataSet);
table[j] = dataSet.Tables[0];
}
return table;
}
Thanks for the help.
The problem here is your dataSet, is declared outsife the for. Each datatable array item is getting the same information. dataSet.Tables[0]; You must declare inside the for. Each iteration store different information.
for (int j = 0; j < excelSheets.Length; j++)
{
DataSet dataSet = new DataSet();
string query = String.Format("SELECT * FROM [" + excelSheets[j] + "]");
.....
}

SQL query to select a range

I need to write an sql query (in c#) to select excel sheet data in only the "C" column starting from C19. But i cant specify the ending cell number because more data are getting added to the column. Hence i need to know how to specify the end of the column. Please help. I have mentioned the query that i'm using. And I have attached an image of the excel sheet that i'm using!.And I have attached the output datagridview!
//Generte Oracle Datatable
OleDbConnection conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;"
+ #"Data Source=" + textBox1.Text + ";" + #"Extended Properties=""Excel 12.0 Macro;HDR=Yes""");
conn.Open();
OleDbCommand ccmd = new OleDbCommand(#"Select * From [SPAT$]", conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(ccmd);
DataTable Oracle = new DataTable();
adapter.Fill(Oracle);
for (int y = 19; y < Oracle.Rows.Count; y++)
{
var value = Oracle.Rows[y][3].ToString();
}
dataGridView1.DataSource = Oracle.AsEnumerable().Where((row, index) => index > 3).CopyToDataTable();
First Approach, using OLE Query:
OleDbCommand ccmd = new OleDbCommand(#"Select * From [SPAT$]", conn);
OleDbDataAdapter da = new OleDbDataAdapter(ccmd);
DataTable dt = new DataTable();
da.Fill(dt);
for (int i = 19; i < dt.Rows.Count; i++)
{
var value = dt.Rows[i][3].ToString(); // here 3 refers to column 'C'
}
For criteria based DataTable
dataGridView1.DataSource = dt.AsEnumerable()
.Where((row, index) => index >= 19)
.CopyToDataTable();
For Column "C" only
dataGridView1.DataSource = dt.AsEnumerable()
.Where((row, index) => index >= 19)
.Select(t => t[3].ToString()).ToList();
Second Approach, using Excel COM object:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open("path to book");
Excel.Worksheet xlSheet = xlWorkbook.Sheets[1]; // get first sheet
Excel.Range xlRange = xlSheet.UsedRange; // get the entire used range
int numberOfRows = xlRange.Rows.Count;
List<string> columnValue = new List<string>();
// loop over each column number and add results to the list
int c = 3; // Column 'C'
for(int r = 19; r <= numberOfRows; r++)
{
if(xlRange.Cells[r,c].Value2 != null) // ADDED IN EDIT
{
columnValue.Add(xlRange.Cells[r,c].Value2.ToString());
}
}

Categories

Resources