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#)
Related
I need to find all the multiple or non-autoincremented primary keys, make them normal keys, and make the primary key an autoincrement column. But I need to check if there is already an autoincrement column, so I make that one a primary key, in case if it's not.
Based on this Microsoft article on How To Retrieve Column Schema by Using the DataReader GetSchemaTable Method and Visual C# .NET I have written a little code for you to pick the field with the auto increment set to True,
OleDbConnection cn = new OleDbConnection();
OleDbCommand cmd = new OleDbCommand();
DataTable schemaTable;
OleDbDataReader myReader;
//Open a connection to the SQL Server Northwind database.
cn.ConnectionString = "...";
cn.Open();
//Retrieve records from the Employees table into a DataReader.
cmd.Connection = cn;
cmd.CommandText = "SELECT * FROM Employees";
myReader = cmd.ExecuteReader(CommandBehavior.KeyInfo);
//Retrieve column schema into a DataTable.
schemaTable = myReader.GetSchemaTable();
var myAutoIncrements = schemaTable.Rows.Cast<DataRow>().Where(
myField => myField["IsAutoIncrement"].ToString() == "True");
foreach (var myAutoInc in myAutoIncrements)
{
Console.WriteLine((myAutoInc[0]));
}
Console.ReadLine();
//Always close the DataReader and connection.
myReader.Close();
cn.Close();
You can simply paste this on you app or even a new console app and see the results of shown Fields with the IsAutoIncrement set to true.
OleDbReader has a GetSchemaTable method. You can call that with a basic select to each table, then loop through the returned columns and check for IsAutoIncrement.
https://msdn.microsoft.com/en-us/library/system.data.oledb.oledbdatareader.getschematable(v=vs.110).aspx
How can I create a named sheet without headers - just like the default sheet - via ace.oledb?
The create command for a sheet must be something like:
CREATE TABLE [MySheet] (field1 type, field2 type ..., fieldn type )
It creates MySheet and always insert (regardless of HDR extended property in connection string or the registry setting FirstRowHasNames) a first line in MySheet containing field1, field2...fieldn
Basically I don't want a "Table Header" there, I just need to insert values in a newly created named empty sheet.
This isn't pretty, but it's the only way I've found to create a new worksheet with nothing in it. The only problem I've discovered is that Oledb automatically creates a named range on the header cells specified in the CREATE command, but assuming you don't care about that then this should work fine.
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName +
";Mode=ReadWrite;Extended Properties=\"Excel 12.0 XML;HDR=NO\"";
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = conn;
cmd.CommandText = "CREATE TABLE [MySheet] (<colname> <col type>)"; // Doesn't matter what the field is called
cmd.ExecuteNonQuery();
cmd.CommandText = "UPDATE [MySheet$] SET F1 = \"\"";
cmd.ExecuteNonQuery();
}
conn.Close();
}
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.
OLEDB can be used to read and write Excel sheets. Consider the following code example:
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\my\\excel\\file.xls;Extended Properties='Excel 8.0;HDR=Yes'")) {
conn.Open();
OleDbCommand cmd = new OleDbCommand("CREATE TABLE [Sheet1] ([Column1] datetime)", conn);
cmd.ExecuteNonQuery();
cmd = new OleDbCommand("INSERT INTO Sheet1 VALUES (#mydate)", conn);
cmd.Parameters.AddWithValue("#mydate", DateTime.Now.Date);
cmd.ExecuteNonQuery();
}
This works perfectly fine. Inserting numbers, text, etc. also works well. However, inserting a value with a time component fails:
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\my\\excel\\file.xls;Extended Properties='Excel 8.0;HDR=Yes'")) {
conn.Open();
OleDbCommand cmd = new OleDbCommand("CREATE TABLE [Sheet1] ([Column1] datetime)", conn);
cmd.ExecuteNonQuery();
cmd = new OleDbCommand("INSERT INTO Sheet1 VALUES (#mydate)", conn);
cmd.Parameters.AddWithValue("#mydate", DateTime.Now); // <-- note the difference here
cmd.ExecuteNonQuery();
}
Executing this INSERT fails with an OleDbException: Data type mismatch in criteria expression.
Is this a known bug? If yes, what can be done to workaround it? I've found one workaround that works:
cmd = new OleDbCommand(String.Format(#"INSERT INTO Sheet1 VALUES (#{0:dd\/MM\/yyyy HH:mm:ss}#)", DateTime.Now), conn);
It basically creates an SQL statement that looks like this: INSERT INTO Sheet1 VALUES (#05/29/2011 13:12:01#). Of course, I don't have to tell you how ugly this is. I'd much rather have a solution with a parameterized query.
It appears to be a known bug https://connect.microsoft.com/VisualStudio/feedback/details/94377/oledbparameter-with-dbtype-datetime-throws-data-type-mismatch-in-criteria-expression
You might want to truncate the milisecond like this it appear to work for OleDbParameter:
DateTime org = DateTime.UtcNow;
DateTime truncatedDateTime = new DateTime(org.Year, org.Month, org.Day, org.Hour, org.Minute, org.Second);
And add this instead of the DateTime.Now into your parameter value.
The problem is the cell containing datetime value cannot be directly put into excel' column. You have to either insert the date component or the time component. The reason for failure is the default property of excel' cell is "values" instead of "datetime" in excel.
I've written a small form that reads the data from a database table (SQL CE 3.5) and displays it in a DataGridView control. This works fine. I then modified it to make a change to the data before displaying it, which also seems to work fine with the exception that it doesn't seem to actually commit the changes to the database. The code is as follows:
using (SqlCeConnection conn = new SqlCeConnection(
Properties.Settings.Default.Form1ConnectionString
)) {
conn.Open();
using (SqlCeDataAdapter adapter = new SqlCeDataAdapter(
"SELECT * FROM People", conn
)) {
//Database update command
adapter.UpdateCommand = new SqlCeCommand(
"UPDATE People SET name = #name " +
"WHERE id = #id", conn);
adapter.UpdateCommand.Parameters.Add(
"#name", SqlDbType.NVarChar, 100, "name");
SqlCeParameter idParameter = adapter.UpdateCommand.Parameters.Add(
"#id", SqlDbType.Int);
idParameter.SourceColumn = "id";
idParameter.SourceVersion = DataRowVersion.Original;
//Create dataset
DataSet myDataSet = new DataSet("myDataSet");
DataTable people = myDataSet.Tables.Add("People");
//Edit dataset
adapter.Fill(myDataSet, "People");
people.Rows[0].SetField("name", "New Name!");
adapter.Update(people);
//Display the table contents in the form datagridview
this.dataGridView1.DataSource=people;
}
}
The form displays like so:
Looking at the table via Visual Studio's Server Explorer however, doesn't show any change to the table.
What am I doing wrong?
I found it. It took days but I found it.
Properties.Settings.Default.Form1ConnectionString is "Data Source=|DataDirectory|\Form1.sdf". The update works if I replace the automatically generated "|DataDirectory|" with the actual path. Oddly enough reading from the database works either way.
Shouldn't the update line be
adapter.Update(myDataSet, "People")
I would make sure the DataSet believes it's been changed. Invoke DataSet.HasChanges (returns bool) and DataSet.GetChanges, which returns a delta of the DataSet from the original.
Have you also tried this against Sql Server Express just to eliminate any issues with the CE data adapter?