I have the following code :
OleDbDataReader xlsReader =
new OleDbCommand("Select * from [" +spreadSheetName + "]", xlsFileConnection).
ExecuteReader();
In the spreadSheetName parameter i keep my file name.
The connection string for xlsFileConnection was set as
"Provider=Microsoft.Jet.OLEDB.4.0;
Data Source='<directory path>';
Extended Properties='text; HDR=No; FMT=Delimited'"
When i start to execute while (xlsReader.Read()) i take a row #2 but not #1 from data source.
The first suggestion was that HDR parameter has invalid value but it seems it's ok.
There are better and easier ways to reading xlsx files, if I were you I would grab closedXML from nuget and this code to read your excel file into a data table
public void ProcessExcel(string fileName)
{
_dt = ImportSheet(fileName);
dgContacts.ItemsSource = _dt.DefaultView;
}
public static DataTable ImportSheet(string fileName)
{
var datatable = new DataTable();
var workbook = new XLWorkbook(fileName);
var xlWorksheet = workbook.Worksheet(1);
var range = xlWorksheet.Range(xlWorksheet.FirstCellUsed(), xlWorksheet.LastCellUsed());
var col = range.ColumnCount();
var row = range.RowCount();
datatable.Clear();
for (var i = 1; i <= col; i++)
{
var column = xlWorksheet.Cell(1, i);
datatable.Columns.Add(column.Value.ToString());
}
var firstHeadRow = 0;
foreach (var item in range.Rows())
{
if (firstHeadRow != 0)
{
var array = new object[col];
for (var y = 1; y <= col; y++)
{
array[y - 1] = item.Cell(y).Value;
}
datatable.Rows.Add(array);
}
firstHeadRow++;
}
return datatable;
}
The grab the data out of your datatable as you need.
This is live and working code, so you just need to copy and paste
Related
I have a SSIS package which is pulling data from a SQL database and generating a comma delimited flat file. The flat file is to be used to import the data into a system and it is causing issues with the text field values in the file as it contains comma in the value.
I am now told to insert the pipe character | as the text qualifier for all text fields.
Example
1234,Smith, John,5678 should be 1234,|Smith, John|,5678
I followed the tutorial in this link to create my SSIS package for the export. It is using a Script Task with the Visual C# script pasted below, which I finding it difficult on how to modify to prepend and append the pipe character to the text values consisting the comma character.
I think it is this part where I will need to insert the pipe character, but I do not know the C# language enough to modify it as needed. Any help or reference resource would be really helpful and appreciated.
StreamWriter sw = null;
sw = new StreamWriter(FileFullPath, false);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
sw.Write(d_table.Columns[ic]);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(dr[ir].ToString());
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
string datetime = DateTime.Now.ToString("yyyyMMddHHmmss");
try
{
//Declare Variables
string DestinationFolder = Dts.Variables["User::DestinationFolder"].Value.ToString();
string FileDelimiter = Dts.Variables["User::FileDelimiter"].Value.ToString();
string FileExtension = Dts.Variables["User::FileExtension"].Value.ToString();
//USE ADO.NET Connection from SSIS Package to get data from table
SqlConnection myADONETConnection = new SqlConnection();
myADONETConnection = (SqlConnection)(Dts.Connections["DBConn"].AcquireConnection(Dts.Transaction) as SqlConnection);
//Read list of Tables with Schema from Database
string query = "SELECT Schema_name(schema_id) AS SchemaName,name AS TableName FROM sys.tables WHERE is_ms_shipped = 0";
//MessageBox.Show(query.ToString());
SqlCommand cmd = new SqlCommand(query, myADONETConnection);
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
//Loop through datatable(dt) that has schema and table names
foreach (DataRow dt_row in dt.Rows)
{
string SchemaName = "";
string TableName = "";
object[] array = dt_row.ItemArray;
SchemaName = array[0].ToString();
TableName = array[1].ToString();
string FileFullPath =DestinationFolder +"\\"+ SchemaName+"_"+TableName + "_" + datetime+FileExtension;
//Get the data for a table into data table
string data_query = "Select * From ["+SchemaName+"].["+TableName+"]";
SqlCommand data_cmd = new SqlCommand(data_query, myADONETConnection);
DataTable d_table = new DataTable();
d_table.Load(data_cmd.ExecuteReader());
StreamWriter sw = null;
sw = new StreamWriter(FileFullPath, false);
// Write the Header Row to File
int ColumnCount = d_table.Columns.Count;
for (int ic = 0; ic < ColumnCount; ic++)
{
sw.Write(d_table.Columns[ic]);
if (ic < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
// Write All Rows to the File
foreach (DataRow dr in d_table.Rows)
{
for (int ir = 0; ir < ColumnCount; ir++)
{
if (!Convert.IsDBNull(dr[ir]))
{
sw.Write(dr[ir].ToString());
}
if (ir < ColumnCount - 1)
{
sw.Write(FileDelimiter);
}
}
sw.Write(sw.NewLine);
}
sw.Close();
Dts.TaskResult = (int)ScriptResults.Success;
}
}
catch (Exception exception)
{
// Create Log File for Errors
using (StreamWriter sw = File.CreateText(Dts.Variables["User::LogFolder"].Value.ToString() + "\\" +
"ErrorLog_" + datetime + ".log"))
{
sw.WriteLine(exception.ToString());
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
Is the package somewhat hard-code query written for getting data and what will be made available for the export process? If so, is the data ONLY for export process from the query? Or is it query data, show some report, then allow the export to comma separated list from same results?
I know, bunch of questions. But if your query is exclusively to pull the data for export, why not tack on the pipes as you query the data, something like
select
SomeIntegerColumn,
'|' + SomeStringField + '|' as SomeStringField,
'|' + AnotherString + '|' as AnotherString
SomeDateColumn,
etc
from
...
Then the data is already formatted for you ready to go.
I am looking for a way to apply a table style to the inserted data in an excel file.
I use the library closed xml
How can I do it?
Sample table I want to get
using (XLWorkbook wb = new XLWorkbook(excel))
{ IXLWorksheet ws = wb.Worksheets.Last();
string Qry;
using (SqlCommand cmd = new SqlCommand(Qry, sqlConn))
{
sqlConn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
System.Data.DataTable schemaTable = dr.GetSchemaTable();
int i = 1;
foreach (DataRow rowt in schemaTable.Rows)
{
while (dr.Read())
{
row++;
for (int j = 0; j < dr.FieldCount; j++)
{
if (!dr.IsDBNull(j))
{
switch (dr.GetDataTypeName(j))
{
case "Varchar2":
string s = dr.GetString(j);
if (s.Substring(0, 1) == "=")
s = " " + s;
ws.Cell(row, j + 1).Value = s;
break;
case "nvarchar":
ws.Cell(row, j + 1).Value = dr.GetString(j);
break;
default:
break;
}}}}}}}
Based on the ClosedXML documentation:
// create the Excel workbook
var wb = new XLWorkbook();
// creates the worksheet
var ws = wb.AddWorksheet("Sheet1");
// the range for which you want to add a table style
var range = ws.Range(1, 1, 5, 5);
// create the actual table
var table = range.CreateTable();
// apply style
namesTable.Theme = XLTableTheme.TableStyleLight12;
Here I have this Import from excel file to sql database class. It was working correctly till now but as my excel file cells are all strings type , So when Importing , the datatype does not match as sql database. How to convert it to their respective datatype before importing?
public static void ImportToSql(string excelfilepath)
{
string myexceldataquery = "select LocalSKU,ItemName, QOH,Price,Discontinued,Barcode,Integer2,Integer3,SalePrice,SaleOn,Price2 from [sheet1$]";
try
{
string sexcelconnectionstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source =" + excelfilepath + "; Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=2\"";
string ssqlconnectionstring = "Data Source=DELL\\SQLSERVER1;Trusted_Connection=True;DATABASE=Test;CONNECTION RESET=FALSE";
SqlConnection sqlconn = new SqlConnection(ssqlconnectionstring);
//series of commands to bulk copy data from the excel file into our sql table
OleDbConnection oledbconn = new OleDbConnection(sexcelconnectionstring);
OleDbCommand oledbcmd = new OleDbCommand(myexceldataquery, oledbconn);
oledbconn.Open();
OleDbDataReader dr = oledbcmd.ExecuteReader();
SqlCommand sqlcmd = new SqlCommand(#"MERGE Inventory AS target
USING (select LocalSKU,ItemName, QOH,Price,Discontinued,Barcode,Integer2,Integer3,SalePrice,SaleOn,Price2 from #source) as source
ON (source.LocalSKU = target.LocalSKU)
WHEN MATCHED THEN
UPDATE SET ItemName=source.ItemName,Price=source.Price,Discontinued=source.Discontinued,Barcode=source.Barcode,Integer2=source.Integer2,Integer3 = source.QOH,SalePrice=source.SalePrice,SaleOn=source.SaleOn,Price2=source.Price2;", sqlconn);
SqlParameter param;
param = sqlcmd.Parameters.AddWithValue("#source",dr);
param.SqlDbType = SqlDbType.Structured;
param.TypeName = "dbo.InventoryType";
sqlconn.Open();
sqlcmd.ExecuteNonQuery();
sqlconn.Close();
while (dr.Read())
{
}
oledbconn.Close();
Console.WriteLine(".xlsx file imported succssessfully into database.");
}
The easiest thing to do would be to convert them in your SQL statement by using CAST:
SqlCommand sqlcmd = new SqlCommand(
#"MERGE Inventory AS target
USING (select LocalSKU, ItemName, QOH = CAST(QOH AS int)
, Price = CAST(Price AS decimal(10,2)), Discontinued = CAST(Discontinued AS bit)
, Barcode, Integer2 = CAST(Integer2 AS int)
, Integer3 = CAST(Integer3 AS int), SalePrice = CAST(SalePrice AS decimal(10,2))
, SaleOn, Price2 = CAST(Price2 AS decimal(10,2)) from #source) as source
ON (source.LocalSKU = target.LocalSKU)
WHEN MATCHED THEN
UPDATE (. . . )
I'm guessing on some of the conversions, but you get the idea. You'll need to make sure that the data in the spreadsheet all match the datatypes you want to convert them to, as one mistake will cause the whole statement to fail. Something more robust will take a lot more code.
First browse the excel file and put data in datagrid and then read datagrid row one by one.
i give you 2 function for that. one is browse the excel file and put data in datagrid and second one is read datagrid and put record in database
Excel Export Function
private void export_btn_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application ExcelApp =
new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook ExcelBook;
Microsoft.Office.Interop.Excel._Worksheet ExcelSheet;
int i = 0;
int j = 0;
//create object of excel
ExcelBook = (Microsoft.Office.Interop.Excel._Workbook)ExcelApp.Workbooks.Add(1);
ExcelSheet = (Microsoft.Office.Interop.Excel._Worksheet)ExcelBook.ActiveSheet;
//export header
for (i = 1; i <= this.dataGridView1.Columns.Count; i++)
{
ExcelSheet.Cells[1, i] = this.dataGridView1.Columns[i - 1].HeaderText;
}
//export data
for (i = 1; i <= this.dataGridView1.RowCount; i++)
{
for (j = 1; j <= dataGridView1.Columns.Count; j++)
{
ExcelSheet.Cells[i + 1, j] = dataGridView1.Rows[i - 1].Cells[j - 1].Value;
}
}
ExcelApp.Visible = true;
//set font Khmer OS System to data range
Microsoft.Office.Interop.Excel.Range myRange = ExcelSheet.get_Range(
ExcelSheet.Cells[1, 1],
ExcelSheet.Cells[this.dataGridView1.RowCount + 1,
this.dataGridView1.Columns.Count]);
Microsoft.Office.Interop.Excel.Font x = myRange.Font;
x.Name = "Arial";
x.Size = 10;
//set bold font to column header
myRange = ExcelSheet.get_Range(ExcelSheet.Cells[1, 1],
ExcelSheet.Cells[1, this.dataGridView1.Columns.Count]);
x = myRange.Font;
x.Bold = true;
//autofit all columns
myRange.EntireColumn.AutoFit();
ExcelApp.ActiveWorkbook.SaveCopyAs("E:\\reports.xlsx");
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
MessageBox.Show("Excel file created,you can find the file E:\\reports.xlsx");
//
ExcelSheet = null;
ExcelBook = null;
ExcelApp = null;
}
Read Datagrid
public void readDataGrid()
{
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
try
{
//Here read one by one cell and convert it into your required datatype and store it in
String rowcell1 = dataGridView1.Rows[i].Cells[0].Value.ToString();
}
catch (Exception err)
{
}
count++;
}
}
I this is help you.
I am looking for a way to create, modify, read .xlsx files in C# without installing Excel or creating files on the server before giving to the user to download.
I found NPOI http://npoi.codeplex.com/ which looks great but supports .xls not .xlsx
I found ExcelPackage http://excelpackage.codeplex.com/ which looks great but has the additional overhead of creating the file on the server before it can be sent to the user.
Does anyone know of a way around this?
I found EPPlus http://epplus.codeplex.com but I am not not certain if this requires creation of a file on the server before it can be sent to the user?
I am pretty new to this so any guidance/examples etc., would be very much appreciated.
With EPPlus it's not required to create file, you can do all with streams, here is an example of ASP.NET ashx handler that will export datatable into excel file and serve it back to the client :
public class GetExcel : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var dt = DBServer.GetDataTable("select * from table");
var ms = GetExcel.DataTableToExcelXlsx(dt, "Sheet1");
ms.WriteTo(context.Response.OutputStream);
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.AddHeader("Content-Disposition", "attachment;filename=EasyEditCmsGridData.xlsx");
context.Response.StatusCode = 200;
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
public static MemoryStream DataTableToExcelXlsx(DataTable table, string sheetName)
{
var result = new MemoryStream();
var pack = new ExcelPackage();
var ws = pack.Workbook.Worksheets.Add(sheetName);
int col = 1;
int row = 1;
foreach (DataRow rw in table.Rows)
{
foreach (DataColumn cl in table.Columns)
{
if (rw[cl.ColumnName] != DBNull.Value)
ws.Cells[row, col].Value = rw[cl.ColumnName].ToString();
col++;
}
row++;
col = 1;
}
pack.SaveAs(result);
return result;
}
}
http://msdn.microsoft.com/en-us/library/cc850837.aspx
Try to use this code to export the data to excel, may it ll help
public static void DataSetsToExcel(DataSet dataSet, string filepath)
{
try
{
string connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filepath + ";Extended Properties=Excel 12.0 Xml;";
string tablename = "";
DataTable dt = new DataTable();
foreach (System.Data.DataTable dataTable in dataSet.Tables)
{
dt = dataTable;
tablename = dataTable.TableName;
using (OleDbConnection con = new OleDbConnection(connString))
{
con.Open();
StringBuilder strSQL = new StringBuilder();
strSQL.Append("CREATE TABLE ").Append("[" + tablename + "]");
strSQL.Append("(");
for (int i = 0; i < dt.Columns.Count; i++)
{
strSQL.Append("[" + dt.Columns[i].ColumnName + "] text,");
}
strSQL = strSQL.Remove(strSQL.Length - 1, 1);
strSQL.Append(")");
OleDbCommand cmd = new OleDbCommand(strSQL.ToString(), con);
cmd.ExecuteNonQuery();
for (int i = 0; i < dt.Rows.Count; i++)
{
strSQL.Clear();
StringBuilder strfield = new StringBuilder();
StringBuilder strvalue = new StringBuilder();
for (int j = 0; j < dt.Columns.Count; j++)
{
strfield.Append("[" + dt.Columns[j].ColumnName + "]");
strvalue.Append("'" + dt.Rows[i][j].ToString().Replace("'", "''") + "'");
if (j != dt.Columns.Count - 1)
{
strfield.Append(",");
strvalue.Append(",");
}
else
{
}
}
if (strvalue.ToString().Contains("<br/>"))
{
strvalue = strvalue.Replace("<br/>", Environment.NewLine);
}
cmd.CommandText = strSQL.Append(" insert into [" + tablename + "]( ")
.Append(strfield.ToString())
.Append(") values (").Append(strvalue).Append(")").ToString();
cmd.ExecuteNonQuery();
}
con.Close();
}
}
}
catch (Exception ex)
{
}
}
Can anyone suggest me how to read excel files in c# using ado.net in disconnected mode.My excel file is quite large and cant be kept in memory.please suggest a method of loading the data into a dataset.
for now i am reading them by using Excel = Microsoft.Office.Interop.Excel and adding the excel reference(com) and then using objects like range etc.
May be this is what you are looking for
http://exceldatareader.codeplex.com/
Id say connect to it with ADO and treat it like a database:
http://www.connectionstrings.com/excel
Here is an example of the what I am using that might be handy for anyone else wanting to get data from an Excel spreadsheet.
It loads each worksheet into a DataTable within a DataSet.
It assumes that you have your headers going from A1 to x1.
using System;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
public class clsExcelWriter : IDisposable
{
private Excel.Application oExcel;
private Excel._Workbook oBook;
private Excel._Worksheet oSheet;
// Used to store the name of the current file
public string FileName
{
get;
private set;
}
public clsExcelWriter(string filename)
{
// Initialize Excel
oExcel = new Excel.Application();
if (!File.Exists(filename))
{
// Create a new one?
}
else
{
oBook = (Excel._Workbook)oExcel.Workbooks.Open(filename);
oSheet = (Excel._Worksheet)oBook.ActiveSheet;
}
this.FileName = filename;
// Supress any alerts
oExcel.DisplayAlerts = false;
}
private string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
public void Dispose()
{
// Lets make sure we release those COM objects!
if (oExcel != null)
{
Marshal.FinalReleaseComObject(oSheet);
oBook.Close();
Marshal.FinalReleaseComObject(oBook);
oExcel.Quit();
Marshal.FinalReleaseComObject(oExcel);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
public static DataSet OpenFile(string filename)
{
DataSet ds = new DataSet();
using (clsExcelWriter xl = new clsExcelWriter(filename))
{
// Iterate through each worksheet
foreach (Excel._Worksheet sheet in xl.oBook.Worksheets)
{
// Create a new table using the sheets name
DataTable dt = new DataTable(sheet.Name);
// Get the first row (where the headers should be located)
object[,] xlValues = (object[,])sheet.get_Range("A1", xl.GetExcelColumnName(sheet.UsedRange.Columns.Count) + 1).Value;
// Iterate through the values to add new DataColumns to the DataTable
for (int i = 0; i < xlValues.GetLength(1); i++)
{
dt.Columns.Add(new DataColumn(xlValues[1, i + 1].ToString()));
}
// Now get the rest of the rows
xlValues = (object[,])sheet.get_Range("A2", xl.GetExcelColumnName(sheet.UsedRange.Columns.Count) + sheet.UsedRange.Rows.Count).Value;
for (int row = 0; row < xlValues.GetLength(0); row++)
{
DataRow dr = dt.NewRow();
for (int col = 0; col < xlValues.GetLength(1); col++)
{
// xlValues array starts from 1, NOT 0 (just to confuse yee)
dr[dt.Columns[col].ColumnName] = xlValues[row + 1, col + 1];
}
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
}
}
// Your DataSet should now be filled! :)
return ds;
}
}
}
Usage
using System.Data;
using ExcelWriter;
namespace Test
{
class Program
{
static void Main(string[] args)
{
DataSet ds = clsExcelWriter.OpenFile(#"C:\Results.xls");
// Do some fancy stuff with the DataSet! xD
while (true) ;
}
}
}
Here what I use to read data from an Excel sheet:
private DbDataReader ReadExcelSheet(string file, string sheet)
{
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + file + ";Extended Properties=Excel 8.0;";
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = connStr;
DbCommand command = connection.CreateCommand();
string query = BuildSelectQuery(sheet, names_mapping);//you need column names here
command.CommandText = query;
connection.Open();
DbDataReader dr = command.ExecuteReader();
return dr;
}