I'm new to c#.net
I have excel sheet and I want to import into database.
I want to read it cell by cell and want to insert value in database.
this.openFileDialog1.FileName = "*.xls";
DialogResult dr = this.openFileDialog1.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
string path = openFileDialog1.FileName;
string connectionString = String.Format(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=""Excel 8.0;HDR=no;IMEX=1;""", openFileDialog1.FileName);
string query = String.Format("select * from [{0}$]", "Sheet3");
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(query, connectionString);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
dataGridView1.DataSource = dataSet.Tables[0];
I assume that after you execute the code in your question, you can see the values within dataGridView1.
The actual reading from the excel sheet is done when calling dataAdapter.Fill. So, in your case, reading the cells comes down to indexing columns and rows in dataSet.Tables[0].
For example:
for (int row = 0; row < dataSet.Tables[0].Rows.Count; row++)
{
DataRow r = dataSet.Tables[0].Rows[row];
}
Accessing the cells in row r is trivial (like the sample above, just for cell).
EDIT
I forgot to describe the "insert the values into a database" part. I presume that the database is SQL Server (may be Express edition, too).
First: create a database connection. Instead of manually composing the connection string, use the SqlConnectionStringBuilder:
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
csb.DataSource = <your server instance, e.g. "localhost\sqlexpress">;
csb.InitialCatalog = <name of your database>;
csb.IntegratedSecurity = <true if you use integrated security, false otherwise>;
if (!csb.IntegratedSecurity)
{
csb.UserId = <User name>;
csb.Password = <Password>;
}
Then, create and open a new SqlConnection with the connection string:
using (SqlConnection conn = new SqlConnection(csb.ConnectionString))
{
conn.Open();
Iterate over all the values you want to insert and execute a respective insert command:
for (...)
{
SqlCommand cmd = new SqlCommand("INSERT INTO ... VALUES (#param1, ..., #paramn)", conn);
cmd.Parameters.AddWithValue("#param1", value1);
...
cmd.Parameters.AddWithValue("#paramn", valuen);
cmd.ExecuteNonQuery();
}
This closes the connection, as the using block ends:
}
And there you go. Alternatively, you could use a data adapter with a special insert-command. Then, inserting the values would come down to a one-liner, however, your database table must have the same structure as the Excel-sheet (respectively: as the data table you obtained in the code you posted.
Check out NPOI
http://npoi.codeplex.com/
It's the .NET version of Apache's POI Excel implementation. It'll easily do what you need it to do, and will help avoid some of the problems ( i.e. local copy of Excel, or worse, copy of Excel on the server ) that you'll face when using the Jet provider.
Related
UPDATE:
I have found that this code works! it searches the Excel sheet and only outputs the data I need.
But can anyone explain to me why this works? how does it know that the first line in the spreadsheet is the "index"??
//Coneection String by default empty
string ConStr = "";
//connection string for that file which extantion is .xlsx
ConStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + "C:\\TestExcel.xlsx" + ";Extended Properties='Excel 12.0 XML;HDR=YES;';";
//making query
string query = "SELECT * FROM [lol$] where ID='i2200'";
//Providing connection
OleDbConnection conn = new OleDbConnection(ConStr);
//checking that connection state is closed or not if closed the
//open the connection
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
//create command object
OleDbCommand cmd = new OleDbCommand(query, conn);
// create a data adapter and get the data into dataadapter
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
//fill the Excel data to data set
da.Fill(ds);
foreach (DataRow row in ds.Tables[0].Rows)
{
lblud.Text = "" + row["Hylde"];
}
OLD
I have been trying to do this for several hours now but no matter what i try, I don't end up with the result i want.
So now im "starting from scratch" again. See if I have approached this incorretly.
Question:
I wan't to create a ASPX website that can search my excel sheet for specific data.
Something like Select * from [Sheet1$] where Column A = i2200
then display only Column B and C from that specific row into a Label / two labels.
See picture here: http://itguruen.dk/EXCEL.png
Does anyone have a simple way of doing this?
Thanks in advance!
Jasper
Have you thought about importing the Excel Spreadsheet into a DataTable, and then analyse that DataTable to populate your labels? You can perform SQL queries on DataTables, so you'll be able to extract the exact data you require quite easily (the hardest part will be importing the Excel Spreadsheet into the DataTable).
There's a very detailed report on this process here: http://www.aspsnippets.com/Articles/Read-and-Import-Excel-File-into-DataSet-or-DataTable-using-C-and-VBNet-in-ASPNet.aspx
Update the post so you can see the solution.
Allthough I dont really know why this works??
Hey i'm new to this and from what i managed to pick up this should be working but it doesn't update my local database.
I have a TelemarketingDatabaseDataSet that was auto generated when i created my local database, which then i dragged the table onto the dataset and i guess they're linked.
Now i have this code :
SqlCeConnection connection = new SqlCeConnection();
connection.ConnectionString = TelemarketingTracker.Properties.Settings.Default.TelemarketingDatabaseConnectionString;
TelemarketingDatabaseDataSet ds = new TelemarketingDatabaseDataSet();
// DataTable tbl = new DataTable();
SqlCeDataAdapter adapter = new SqlCeDataAdapter("select * from Calls", connection);
//adapter.InsertCommand = new SqlCeCommand("InsertQuery", connection);
adapter.Fill(ds,"Calls");
DataTable tbl = ds.Tables["Calls"];
//tbl.Columns.Add("caller");
//tbl.Columns.Add("called");
//tbl.Columns.Add("duration");
//tbl.Columns.Add("time");
var row = tbl.NewRow();
row[1] = Convert.ToString(caller);
row[2] = Convert.ToString(called);
row[3] = Convert.ToString(duration);
row[4] = Convert.ToDateTime(time);
tbl.Rows.Add(row);
adapter.Update(ds, "Calls");
connection.Close();
MessageBox.Show("Database should be updated!");
And please, i'm not intrested in using an SqlCommand as i prefer using DataSet.
Could the problem be related to datatypes of my table? it doesn't show errors to suggest that but i guess this could be the problem. my Table consists of :
ID - int,key
caller - varchar
called - varchar
duration - varchar
time - datetime
EDIT:
Now if i uncomment the insertQuery row i get an unhandled error occured in Syste.Data dll.
Now even if i try to use a regular insert command i get no errors but the database won't update.
if this makes any diffrence after i close the debugging window i see an X next to the local database but it doesn't show any errors.
This is the command i've tried :
using (SqlCeCommand com = new SqlCeCommand("INSERT INTO Calls (caller, called, duration, time) Values(#Caller,#Called,#Duration,#Time)", connection))
{
com.Parameters.AddWithValue("#Caller", row[1]);
com.Parameters.AddWithValue("#Called", row[2]);
com.Parameters.AddWithValue("#Duration", row[3]);
com.Parameters.AddWithValue("#Time", row[4]);
com.ExecuteNonQuery();
}
The Fill() method "Adds or refreshes rows in the DataSet to match those in the data source." The key part of this sentence being "to match those in the data source". The row you're adding gets wiped out when you call Fill() because it's not already in the source.
I'm not positive, but I don't think that you need to even call Fill() if you're only adding new records and not worried about modifying/removing existing ones. If you do need to call it though, it would obviously need to be moved before any new record insertions you make.
Try something similar to this..
string dbfile = new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName + "\\TelemarketingDatabase.sdf";
SqlCeConnection connection = new SqlCeConnection("datasource=" + dbfile);
TelemarketingDatabaseDataSet ds = new TelemarketingDatabaseDataSet();
SqlCeDataAdapter adapter = new SqlCeDataAdapter();
string qry = #"select * from Calls";
da.SelectCommand = new SqlCommand(qry, connection);
SqlCommandBuilder cb = new SqlCommandBuilder(adapter);
adapter.Fill(ds,"Calls");
DataTable tbl = ds.Tables["Calls"];
var row = tbl.NewRow();
row[0] = caller;
row[1] = called;
row[2] = duration;
row[3] = Convert.ToDateTime(time);
tbl.Rows.Add(row);
adapter.Update(ds,"Calls");
See the example here http://www.java2s.com/Code/CSharp/Database-ADO.net/UseDataTabletoupdatetableinDatabase.htm
Well in the end i didn't manage to solve this, instead i used a remote database and regular sql commands.
Thanks for those who helped!
just want to share this even the if the question is old
using System;
using System.IO; //needed for path.getdirectoryname() and directory.getcurrentdirectory()
string path = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory()));
AppDomain.CurrentDomain.SetData("DataDirectory", path);
Directory.GetcurrentDirectory() will output "C:/..projectname/bin/debug" which is where the temporary database.mdf is located
by using Path.GetDirectoryName(Directory.GetcurrentDirectory()) it will give the directory of the current directory thus moving one location back
"C:/..projectname/bin"
then use it again
Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) will give you the location of the root database in your project folder
"C:/..projectname"
then just use AppDomain.CurrentDomain.SetData()
I am getting the following error "No value given for one or more required parameters." On the ExceuteNonQuery() line of the below code.
System.Data.OleDb.OleDbConnection finalConnection;
System.Data.OleDb.OleDbCommand myCommand = new System.Data.OleDb.OleDbCommand();
string sql = null;
finalConnection = new System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source ='c:\\temp\\test.xlsx'; Extended Properties ='Excel 12.0 Xml;HDR=NO';");
finalConnection.Open();
myCommand.Connection = finalConnection;
foreach (VinObject v in VinList)
{
sql = "Update [Sheet1$] set O = ? where S = ?;";
myCommand.Parameters.Add(new OleDbParameter("#amt", v.CostNewAmt));
myCommand.Parameters.Add(new OleDbParameter("#vin", v.VIN));
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
}
finalConnection.Close();
I have also tried using a separate command each time, same error.
foreach (VinObject v in VinList)
{
using (OleDbConnection con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0; Data Source ='c:\\temp\\test.xlsx'; Extended Properties ='Excel 12.0 Xml;HDR=No';"))
{
con.Open();
string query = #"UPDATE [Sheet1$] SET O = ? WHERE S = ?";
OleDbCommand cmd = new OleDbCommand(query, con);
cmd.Parameters.AddWithValue("#param1", v.CostNewAmt);
cmd.Parameters.AddWithValue("#param2", v.VIN);
cmd.ExecuteNonQuery();
con.Close();
}
}
I am able to modify that into an insert and insert into a new excel spreadsheet, but for the life of me cannot get this update to work. Any idea what I am doing wrong? Thanks for the help.
You're getting the error because Excel doesn't recognize the column letter aliases "O" and "S". It needs the actual column "name", which is the value of the cell in the first populated row. If there is not a valid value in that cell, or you have specified HDR=NO in your connection string, the columns will be named F1, F2...Fn. If you're not sure what the inferred column names are, examine the names using OleDbConnection.GetSchema(String,String[]) or OleDbDataReader.GetName(Int32).
Since you have specified HDR=NO in your connection string, your correct SQL will likely be
"Update [Sheet1$] set F15 = ? where F19 = ?;"
For future reference, check out:
How to query and display excel data by using ASP.NET, ADO.NET, and Visual C# .NET
How to transfer data to an Excel workbook by using Visual C# 2005 or Visual C# .NET
How To Use ADO.NET to Retrieve and Modify Records in an Excel Workbook With Visual Basic .NET. (Still lots of helpful info even if you are using C#)
I am trying to use ADO.NET to connect to and write to an excel file. I have created a blank file with the default excel sheets (I have also tried with a custom sheet.)
For some reason I am unable to write a full row of data to the sheet. If I create a new sheet it works fine, however then I have too many sheets and I am unable to delete any sheets.
Is there something special you need to do to write a row of data to a blank sheet?
I try to do:
path= the path including my file.
connString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=NO;\"", Server.MapPath(path));
dbCmd.CommandText = "Update [Sheet1$] Set F1 = 'Col1', F2 = 'Col2', F3 = 'Col3', F4 = 'Col4'";
dbCmd.ExecuteNonQuery();
Here's an example of creating a brand new spreadsheet, creating a sheet (Sheet1) and then inserting a row into that. Most of this example was based on a blog entry from David Hayden (great blog entry for this task, btw!!).
Also, you should check out this Microsoft KB article for reading/writing to Excel from ADO.NET -- it really goes into a lot of detail.
//Most of this code was from David Hayden's blog:
// http://www.davidhayden.com/blog/dave/archive/2006/05/26/2973.aspx
static void Main(string[] args)
{
string connectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Temp\TestSO1.xls;Extended Properties=""Excel 8.0;HDR=NO;""";
DbProviderFactory factory =
DbProviderFactories.GetFactory("System.Data.OleDb");
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = connection.CreateCommand())
{
connection.Open(); //open the connection
//use the '$' notation after the sheet name to indicate that this is
// an existing sheet and not to actually create it. This basically defines
// the metadata for the insert statements that will follow.
// If the '$' notation is removed, then a new sheet is created named 'Sheet1'.
command.CommandText = "CREATE TABLE [Sheet1$] (F1 number, F2 char(255), F3 char(128))";
command.ExecuteNonQuery();
//now we insert the values into the existing sheet...no new sheet is added.
command.CommandText = "INSERT INTO [Sheet1$] (F1, F2, F3) VALUES(4,\"Tampa\",\"Florida\")";
command.ExecuteNonQuery();
//insert another row into the sheet...
command.CommandText = "INSERT INTO [Sheet1$] (F1, F2, F3) VALUES(5,\"Pittsburgh\",\"Pennsylvania\")";
command.ExecuteNonQuery();
}
}
}
The only problem I found is that even though the connection string states not to use headers, you still have to define column names for your sheet, and ADO.NET inserts a row when you create the sheet that has the row header names. I can't seem to find a way around that besides going in after I insert everything and removing the first row. Not very elegant.
Hope this helps!! Let me know if you have other questions.
I am reading Excel file using OLEDB in Csharp i have shown the sample excel data what i have
F1 F2 F3 F4
India 23 44 4
China 4 8 Month 6
USA 45 Neg 4
When i read this data and check in my DataTable i get Null values for "Month 6" and "Neg"
where as i can be able get the F1 column correctly... my connection string is as shown
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=[XLSource];Extended Properties=Excel 12.0;
OleDbDataReader dr;
OleDbConnection conExcel = new OleDbConnection();
conExcel.ConnectionString = ConnectionString
conExcel.Open();
OleDbCommand cmdExcel = new OleDbCommand();
cmdExcel.Connection = conExcel;
cmdExcel.CommandText = "SELECT * FROM Sheet1$";
dr = cmdExcel.ExecuteReader();
DataTable dtExcel = new DataTable();
dtExcel.Load(dr);
Try using the IMEX=1 parameter in your connection string (google for more info).
I think what's happening is that Excel is inferring the data type of each column from the first few rows. When it then encounters a value that does not match the inferred data type, it treats it as null.
I had this problem, but rather than setting IMEX=1 I set the registry setting TypeGuessRows to 0 rather than the default 8, I read that IMEX would be needed somewhere but it seems to pick up this registry change either way.
However, I am using the Jet provider rather than Ace so that might make a difference.
For me I found the setting at: Hkey_Local_Machine/Software/Microsoft/Jet/4.0/Engines/Excel/TypeGuessRows
I answered a similar question here. Here I've copied and pasted the same answer for your convenience:
I had this same problem, but was able to work around it without resorting to the Excel COM interface or 3rd party software. It involves a little processing overhead, but appears to be working for me.
First read in the data to get the column names
Then create a new DataSet with each of these columns, setting each of their DataTypes to string.
Read the data in again into this new
dataset. Voila - the scientific
notation is now gone and everything is read in as a string.
Here's some code that illustrates this, and as an added bonus, it's even StyleCopped!
public void ImportSpreadsheet(string path)
{
string extendedProperties = "Excel 12.0;HDR=YES;IMEX=1";
string connectionString = string.Format(
CultureInfo.CurrentCulture,
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"{1}\"",
path,
extendedProperties);
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
using (OleDbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM [Worksheet1$]";
connection.Open();
using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
using (DataSet columnDataSet = new DataSet())
using (DataSet dataSet = new DataSet())
{
columnDataSet.Locale = CultureInfo.CurrentCulture;
adapter.Fill(columnDataSet);
if (columnDataSet.Tables.Count == 1)
{
var worksheet = columnDataSet.Tables[0];
// Now that we have a valid worksheet read in, with column names, we can create a
// new DataSet with a table that has preset columns that are all of type string.
// This fixes a problem where the OLEDB provider is trying to guess the data types
// of the cells and strange data appears, such as scientific notation on some cells.
dataSet.Tables.Add("WorksheetData");
DataTable tempTable = dataSet.Tables[0];
foreach (DataColumn column in worksheet.Columns)
{
tempTable.Columns.Add(column.ColumnName, typeof(string));
}
adapter.Fill(dataSet, "WorksheetData");
if (dataSet.Tables.Count == 1)
{
worksheet = dataSet.Tables[0];
foreach (var row in worksheet.Rows)
{
// TODO: Consume some data.
}
}
}
}
}
}
}
I answered another question much like this one.
In short, the settings that control the ACE driver behavior are located in the registry at:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Access Connectivity Engine\Engines\Excel
Set ImportMixedTypes to Text and set TypeGuessRows to 0 (or some suitably large number like 1000) and you should get the behavior you are expecting.