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());
}
}
Related
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.
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.
I am trying to fetch data from excel using below C# code. I am getting the value from two
columns into single variable(str).
I want that value into different variables.So that i can send that value at runtime for two different statements.
How to bring them into two different variable?
string currentSheet = "Sheet1";
excelApp = new Excel.Application();
//Opening/adding Excel file
excelWorkbook = excelApp.Workbooks.Add(workbookPath);
excelSheets = excelWorkbook.Sheets;
excelWorksheet = (Excel.Worksheet)excelSheets.get_Item(currentSheet);
//Gives the used cells in the sheet
range = excelWorksheet.UsedRange;
for (rowCnt = 1; rowCnt <= range.Rows.Count; rowCnt++)
{
for (colCnt = 1; colCnt <= range.Rows.Count;colCnt++)
{
str = (string)(range.Cells[rowCnt,colCnt] as Excel.Range).Value2;
System.Console.WriteLine(str);
}
}
string Connection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=\"Excel 12.0;HDR=Yes;IMEX=1\";";
OleDbConnection con = new OleDbConnection(Connection);
OleDbCommand command = new OleDbCommand();
System.Data.DataTable dt = new System.Data.DataTable();
OleDbDataAdapter myCommand = new OleDbDataAdapter("select * from [Sheet1$]", con);
myCommand.Fill(dt);
con.Close();
for (rowCnt = 1; rowCnt <= range.Rows.Count; rowCnt++)
{
string Charity = (string)(range.Cells[rowCnt, 1] as Excel.Range).Value;
string Country = (string)(range.Cells[rowCnt, 2] as Excel.Range).Value;
System.Console.WriteLine(Charity + " --- " + Country);
}
I'm writing a windows application with c# and in one form I want to use a n excel file in this way.
In the form when the user types the Employee ID in a text box I wanna search the excel file and based on the ID show other information for the employee in some other text boxes(name text box, last name text box ,status textbox ,and food count text box)
please tell me how can I retrieve the info from it .
public List <string>[] RetrieveColumnGeneral(Excel.Worksheet sheet,string FindWhat)
{
int columnCount = sheet.UsedRange.Columns.Count;
List<string>[] columnValue = new List<string>[columnCount];
Excel.Range rngResult = null;
Excel.Range rng = null;
int index = 0;
int rowCount = sheet.UsedRange.Rows.Count;
Excel.Range FindRange = null;
for (int columnIndex = 1; columnIndex <= sheet.UsedRange.Columns.Count;columnIndex++ )
{
FindRange = sheet.UsedRange.Columns[columnIndex] as Excel.Range;
FindRange.Select();
rngResult = FindRange.Find(What: FindWhat, LookIn: Excel.XlFindLookIn.xlValues,
LookAt: Excel.XlLookAt.xlPart, SearchOrder: Excel.XlSearchOrder.xlByRows);
if (rngResult != null)
{
columnValue[index] = new List<string>();
for (int rowIndex = 1; rowIndex <= sheet.UsedRange.Rows.Count;rowIndex++ )
{
rng = sheet.UsedRange[rowIndex, columnIndex] as Excel.Range;
if (rng.Value != null)
{
columnValue[index].Add(rng.Value.ToString());
}
}
index++;
}
}
Array.Resize ( ref columnValue , index);
return columnValue;
}
thanks I found this code . Will you tell me whether this will solve my problem ?(also by some modifications.)
Try this,
You have to passed Sheet object, but in below code SQL statement fire and get all records in DataSet object.
string sql = "SELECT * FROM [" + selectedWorksheetName + "]";
var adapter = new OleDbDataAdapter(sql, excelObject.Connection);
adapter.Fill(activityDataSet, "Results");
if (activityDataSet.Tables[0] != null)
{
//here you will check which data get based on your columns
}
Try some thing like this.
var ds = new DataSet();
var adapter = new OleDbDataAdapter("SELECT * FROM [" + newSheetName + "]", ConnectionString);
adapter.Fill(ds, newSheetName);
Then use the above dataset to filter the rows.
DataRow dataRow = (from DataRow dr in ds.Tables[0].Rows where dr["Id"] == textbox.Text select dr).FirstOrDefault();
if(dataRow != null)
{
// Fill values from this dataRow
}
EDIT
// If excelsheet ends with .xls
string ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\ExcelData\QB Accounts.xls;Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
// If excelsheet ends with .xlsx
string ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\ExcelData\CSENG01.xlsx;Extended Properties='Excel 12.0;HDR=Yes;IMEX=1'";
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";
}