Can't sort excel worksheet using C# - c#

I want to programmatically sort an excel worksheet using C# but the code I used doesn't work:
//the largest size of sheet in Excel 2010
int maxRowAmount = 1048576;
int maxColAmount = 16384;
//Sort by the value in column G1
sourceWorkSheet.Sort.SortFields.Add(sourceWorkSheet.Range["J:J"], XlSortOn.xlSortOnValues, XlSortOrder.xlAscending, XlSortDataOption.xlSortNormal);
//Find out the last used row and column, then set the range to sort,
//the range is from cell[2,1](top left) to the bottom right corner
int lastUsedRow=sourceWorkSheet.Cells[maxRowAmount, 1].End[XlDirection.xlUp].Row;
int lastUsedColumn=sourceWorkSheet.Cells[2, maxColAmount].End[XlDirection.xlToLeft].Column;
Range r = sourceWorkSheet.Range[sourceWorkSheet.Cells[2, 1], sourceWorkSheet.Cells[lastUsedRow,lastUsedColumn ]];
sourceWorkSheet.Sort.SetRange(r);
//Sort!
sourceWorkSheet.Sort.Apply();
I debug it using the messagebox to print of the value in the column "J" and the result is not sorted:
//print out the sorted result
Range firstColumn = sourceWorkSheet.UsedRange.Columns[10];
System.Array myvalues = (System.Array)firstColumn.Cells.Value;
string[] cmItem = myvalues.OfType<object>().Select(o => o.ToString()).ToArray();
String msg="";
for (int i = 0; i < 30; i++)
{
msg = msg + cmItem[i] + "\n";
}
MessageBox.Show(msg);
What's the reason of it not working?
Thanks

The solution is to put a
sourceWorkSheet.Sort.SortFields.Clear();
before
sourceWorkSheet.Sort.SortFields.Add(sourceWorkSheet.Range["J:J"], XlSortOn.xlSortOnValues, XlSortOrder.xlAscending, XlSortDataOption.xlSortNormal);

In your code you open excel then read from it so sheets are read in original order (not sorted alphabetical).
You can use next code to get sorted sheets.
OleDbConnection connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; Extended Properties=\"Excel 8.0;HDR=No;\"", filePath));
OleDbCommand command = new OleDbCommand();
DataTable tableOfData = null;
command.Connection = connection;
try
{
connection.Open();
tableOfData = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string tablename = tableOfData.Rows[0]["TABLE_NAME"].ToString();
tableOfData = new DataTable();
command.CommandText = "Select * FROM [" + tablename + "]";
tableOfData.Load(command.ExecuteReader());
}
catch (Exception ex)
{
}

Related

Can't export large data from oracle to excel file using c#

I have a problem with extracting large data from oracle table to C#, and I
couldn't find the solution myself.
For this task I wrote a C# code, which loaded data from oracle procedure, which returns cursor, in excel file for the first time.
But when I tried to load bigger table (about 20 columns and 90 000 rows), it just didn't work.
Script doesn't fall with error, but data are not inserted into excel file.
I tried to load for 10 000 rows and then save the results, but again, only 30 000 rows were inserted.
I monitored the counter in loop, it is going correct and reach needed 90 000 and ExecuteNonQuery() always returned the value 10 000. But when I open excel file, there are only 30 000 rows there.
Can you please help me to catch the error, or may be somebody met the same problem, and can advise me what to do or what to read.
Thank you for any help!
I didn't write the connection string, but I think, it's correct, cause script works correctly with small datatable.
public static void Main()
{
string datetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
try
{
OleDbConnection Excel_OLE_Con = new OleDbConnection();
OleDbCommand Excel_OLE_Cmd = new OleDbCommand();
string qwe_constr = "connection string";
OracleConnection myADONETConnection = new OracleConnection(qwe_constr);
string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + "E:\\qaz\\15.07.2016\\qwe" +
";" + "Extended Properties=\"Excel 12.0 Xml;HDR=YES;\"";
File.Delete("E:\\qaz\\15.07.2016\\qwe.xlsx");
//fill datatable with data for insert
myADONETConnection.Open();
OracleCommand cmd_proc = new OracleCommand();
cmd_proc.Connection = myADONETConnection;
cmd_proc.CommandType = System.Data.CommandType.StoredProcedure;
cmd_proc.CommandText = "procedure_name";
cmd_proc.Parameters.Add("p_show_del", OracleDbType.Int16).Value = 0;
cmd_proc.Parameters.Add("p_type", OracleDbType.Varchar2, 3).Value = "INV";
cmd_proc.Parameters.Add("p_errno", OracleDbType.Int16).Value = 157;
cmd_proc.Parameters.Add("outcur", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
DataTable dt_with_data = new DataTable();
dt_with_data.Load(cmd_proc.ExecuteReader());
myADONETConnection.Close();
//string with column headers
string TableColumns = "";
foreach (DataColumn column in dt_with_data.Columns)
{
TableColumns += column + "],[";
}
// Replace most right comma from Columnlist
TableColumns = ("[" + TableColumns.Replace(",", " Text,").TrimEnd(','));
TableColumns = TableColumns.Remove(TableColumns.Length - 2);
//Use OLE DB Connection and Create Excel Sheet
Excel_OLE_Con.ConnectionString = connstring;
Excel_OLE_Con.Open();
Excel_OLE_Cmd.Connection = Excel_OLE_Con;
Excel_OLE_Cmd.CommandText = "Create table [sheet1] (" + TableColumns + ")";
Excel_OLE_Cmd.ExecuteNonQuery();
Excel_OLE_Con.Close();
//Write Data to Excel Sheet from DataTable dynamically
//string with command
Excel_OLE_Con.Open();
String sqlCommandInsert = "";
String sqlCommandValue = "";
foreach (DataColumn dataColumn in dt_with_data.Columns)
{
sqlCommandValue += dataColumn + "],[";
}
sqlCommandValue = "[" + sqlCommandValue.TrimEnd(',');
sqlCommandValue = sqlCommandValue.Remove(sqlCommandValue.Length - 2);
sqlCommandInsert = "INSERT into [sheet1] (" + sqlCommandValue + ") VALUES(";
int columnCount = dt_with_data.Columns.Count;
int i_qaz = 0;
foreach (DataRow row in dt_with_data.Rows)
{
i_qaz++;
Console.WriteLine(i_qaz.ToString());
string columnvalues = "";
for (int i = 0; i < columnCount; i++)
{
int index = dt_with_data.Rows.IndexOf(row);
columnvalues += "'" + dt_with_data.Rows[index].ItemArray[i].ToString().Replace("'", "''") + "',";
}
columnvalues = columnvalues.TrimEnd(',');
var command = sqlCommandInsert + columnvalues + ")";
Excel_OLE_Cmd.CommandText = command;
Excel_OLE_Cmd.ExecuteNonQuery();
}
}
catch (Exception exception)
{
// Create Log File for Errors
using (StreamWriter sw = File.CreateText("E:\\qaz\\15.07.2016\\qwe_" + datetime + ".log"))
{
sw.WriteLine(exception.ToString());
}
}
}
PS: Same question in Russian.

Reading Excel in c# where some columns are empty

I have an Excel template like this
and I have some problems reading this (I can't use 3rd-party libraries). My solution:
public partial class CaricaDocumento : System.Web.UI.Page
{
static string HDR; // "Yes" indicates that the first row contains column names, not data
Regex regex = new Regex("([0-9]+)(.*)");
protected void Page_Load(object sender, EventArgs e)
{
string ind = "C:\\My_Template.xlsx";
string sheetName = "Page1";
DataTable dt = FromXLSX(ind, sheetName, true);
DataToView(dt);
}
// Bind data to the page
private void DataToView(DataTable dt)
{
LblFattura.Text = GetValue("AO10", dt);
LblDataFattura.Text = GetValue("AX10", dt);
LblCognomeOrRagioneSociale.Text = GetValue("B18", dt);
LblNome.Text = GetValue("AB18", dt);
}
// return the value from the cell, indicate a code like "A1", "B3", "AO10"...
public string GetValue(string codeCell, DataTable dt)
{
string[] substrings = regex.Split(codeCell);
string letterString = substrings[0]; // 'A' or 'B' ... 'AZ' ...
int letter = ColumnLetterToNumber(letterString); // transform the letter in a column index
int num = 1;
if (HDR == "Yes")
num = 2;
// if the first row is an header, do -2
// if the first row is a simple data row, do -1
int number = Int32.Parse(substrings[1]) - num; // the right row index
return dt.Rows[number][letter].ToString();
}
// transform the letter in a column index
public static int ColumnLetterToNumber(string columnName)
{
if (string.IsNullOrEmpty(columnName)) throw new ArgumentNullException("columnName");
columnName = columnName.ToUpperInvariant();
int sum = 0;
for (int i = 0; i < columnName.Length; i++)
{
sum *= 26;
char letter = columnName[i];
sum += (letter - ('A' - 1));
}
sum--;
return sum;
}
// return the DataTable
public static DataTable FromXLSX(string filePath, string sheet, bool hasHeaders)
{
try
{
// Create the new datatable.
DataTable dtexcel = new DataTable();
// Define the SQL for querying the Excel spreadsheet.
HDR = hasHeaders ? "Yes" : "No"; // "HDR=Yes;" indicates that the first row contains column names, not data
string IMEX = "1";
string strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath
+ ";Extended Properties=\"Excel 12.0;HDR=" + HDR + ";IMEX=" + IMEX + ";\"";
// Create connection:
OleDbConnection conn = new OleDbConnection(strConn);
conn.Open();
if (!sheet.EndsWith("_"))
{
// Query data from the sheet
string query = "SELECT * FROM [" + sheet + "$]";
OleDbDataAdapter daexcel = new OleDbDataAdapter(query, conn);
dtexcel.Locale = CultureInfo.CurrentCulture;
// Fill the datatable:
daexcel.Fill(dtexcel);
}
// Close connection.
conn.Close();
// Set the datatable.
return dtexcel;
}
catch { throw; }
}
}
But I have noticed this issue: if datas don't start from the column 'A', the DataTable read data from the first column with data! Is a nightmare for the indexes. For example:
... in this case the column 'A' is ignored (the DataTable takes datas starting from 'B') and this invalidates the use of cell codes (like "A1", "B5", "AO11"...) because the method ColumnLetterToNumber(string columnName) is distorted.
Someone knows how I can impose that the DataTable gets datas starting from the 'A' column? Or alternative ways to get data from Excel using cell codes?
You can use this query:
string query = "SELECT NULL AS EmptyColumn, * FROM [" + sheet + "$]";

In Excel how to search a value in a column and get all the values in that row using C#

I am trying searching a value on column "C" and getting a matched cell name as well, for example C14, now how can I select the values in row 14.
I tried as :
private static MyObject GetRowValue(int rowNumber)
{
string connString = "";
string path = "C:\\Code\\MyFile.xls";
connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=2\"";
string query = "SELECT * FROM [Sheet1$A" + rowNumber + ":BD" + rowNumber + "]";
using (OleDbConnection connection = new OleDbConnection(connString))
{
var adapter = new OleDbDataAdapter(query, connection);
DataSet ds = new DataSet();
adapter.Fill(ds);
DataTable dt = ds.Tables[0];
}
}
If row number is 10, them I am trying to get all values of 10th row only, but it is returning all the rows after 10th row.
Just use this formula:
string query = #"SELECT * FROM [Sheet1$"+ (rowNumber-1) + ":" + (rowNumber) + "]";
If rowNumber=10 then you get all the values from the 10th row.
Was this helpful?
If it were me, I'd let Excel do the work for me. You'd need the Office.Interop.Excel namespace.
private static ReadRows(string SearchValue, int StartRow)
{
int r = StartRow;
Excel.Application xl = new Excel.Application();
xl.Workbooks.Open(your workbook);
Excel.WorkSheet ws = xl.Workbooks(1).Worksheets(1);
do
{
if(ws.Cells(r,3).value == SearchValue)
{
// read the entire row
string colA = ws.Cells(r,1).value;
string colB = ws.Cells(r,2).value;
//...
// or loop through all columns
int c = 1;
do
{
// add cell value to some collection
c++;
} while (ws.Cells(r,c).Value != "");
}
r++;
} while (ws.Cells(r,3).Value != ""); // 3 because you want column C
}

How to convert datatype before Importing Excel file to Sql database

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.

Reading columns from Excel, reformat cells

I am currently trying to read in cells from an excel spread sheet, and it seems to reformat cells when I don't want it to. I want it to come through as plan text. I have read a couple of solutions to this problem and I have implemented them, but I am still having the same issue.
The reader turns dates in numbers and numbers into dates.
Example:
Friday, January 29, 2016 comes out to be : 42398
and
40.00 comes out to be : 2/9/1900 12:00:00 AM
code:
string stringconn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + files[0] + ";Extended Properties=\"Excel 12.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text\"";
try {
OleDbConnection conn = new OleDbConnection(stringconn);
OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM [CUAnswers$]", conn);
DataTable dt = new DataTable();
try {
printdt(dt);
I have tried
IMEX=0;
HDR=NO;
TypeGuessRows=1;
This is how I am printing out the sheet
public void printdt(DataTable dt) {
int counter1 = 0;
int counter2 = 0;
string temp = "";
foreach (DataRow dataRow in dt.Rows) {
foreach (var item in dataRow.ItemArray) {
temp += " ["+counter1+"]["+counter2+"]"+ item +", ";
counter2++;
}
counter1++;
logger.Debug(temp);
temp = "";
counter2 = 0;
}
}
I had a similar problem, except it was using Interop to read the Excel spreadsheet. This worked for me:
var value = (range.Cells[rowCnt, columnCnt] as Range).Value2;
string str = value as string;
DateTime dt;
if (DateTime.TryParse((value ?? "").ToString(), out dt))
{
// Use the cell value as a datetime
}
Editted to add new ideas
I was going to suggest saving the spreadsheet as comma-separated values. Then Excel converts the cells to text. It is easy to parse a CSV in C#.
That led me to think of how to programmatically do the conversion, which is covered in Convert xls to csv programmatically. Maybe the code in the accepted answer is what you are looking for:
string ExcelFilename = "c:\\ExcelFile.xls";
DataTable worksheets;
string connectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;" + #"Data Source=" + ExcelFilename + ";" + #"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""";
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
connection.Open();
worksheets = connection.GetSchema("Tables");
foreach (DataRow row in worksheets.Rows)
{
// For Sheets: 0=Table_Catalog,1=Table_Schema,2=Table_Name,3=Table_Type
// For Columns: 0=Table_Name, 1=Column_Name, 2=Ordinal_Position
string SheetName = (string)row[2];
OleDbCommand command = new OleDbCommand(#"SELECT * FROM [" + SheetName + "]", connection);
OleDbDataAdapter oleAdapter = new OleDbDataAdapter();
oleAdapter.SelectCommand = command;
DataTable dt = new DataTable();
oleAdapter.FillSchema(dt, SchemaType.Source);
oleAdapter.Fill(dt);
for (int r = 0; r < dt.Rows.Count; r++)
{
string type1 = dr[1].GetType().ToString();
string type2 = dr[2].GetType().ToString();
string type3 = dr[3].GetType().ToString();
string type4 = dr[4].GetType().ToString();
string type5 = dr[5].GetType().ToString();
string type6 = dr[6].GetType().ToString();
string type7 = dr[7].GetType().ToString();
}
}
}

Categories