I need to help to generate column name from excel automatically. I think that: we can do below codes:
CREATE TABLE [dbo].[Addresses_Temp] (
[FirstName] VARCHAR(20),
[LastName] VARCHAR(20),
[Address] VARCHAR(50),
[City] VARCHAR(30),
[State] VARCHAR(2),
[ZIP] VARCHAR(10)
)
via C#. How can I learn column name from Excel?
private void Form1_Load(object sender, EventArgs e)
{
ExcelToSql();
}
void ExcelToSql()
{
string connectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Source\MPD.xlsm;Extended Properties=""Excel 12.0;HDR=YES;""";
// if you don't want to show the header row (first row)
// use 'HDR=NO' in the string
string strSQL = "SELECT * FROM [Sheet1$]";
OleDbConnection excelConnection = new OleDbConnection(connectionString);
excelConnection.Open(); // This code will open excel file.
OleDbCommand dbCommand = new OleDbCommand(strSQL, excelConnection);
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(dbCommand);
// create data table
DataTable dTable = new DataTable();
dataAdapter.Fill(dTable);
// bind the datasource
// dataBingingSrc.DataSource = dTable;
// assign the dataBindingSrc to the DataGridView
// dgvExcelList.DataSource = dataBingingSrc; // dispose used objects
if (dTable.Rows.Count > 0)
MessageBox.Show("Count:" + dTable.Rows.Count.ToString());
dTable.Dispose();
dataAdapter.Dispose();
dbCommand.Dispose();
excelConnection.Close();
excelConnection.Dispose();
}
You should be able to iterate over the DataTable's columns collection to get the column names.
System.Data.DataTable dt;
dt = new System.Data.DataTable();
foreach(System.Data.DataColumn col in dt.Columns)
{
System.Diagnostics.Debug.WriteLine(col.ColumnName);
}
Does it have to be C#? If you're willing to use Java, I've had really good results with Apache POI: http://poi.apache.org/
This is not a C# solution... it is a quick and dirty solution right from excel.
A c# solution would be more robust and allow you to most likely point it to a target xls and have it give you the answers - this solution is for if you need the answers fast and don't have time to write a program or if someone does not have C# development environment on their computer.
One possible way to get the results you're looking for is:
highlight the row in excel that has the column headers
copy them
go to a new worksheet
right click cell A1
click paste-transpose
it will paste them in column format
go to B2 and paste this formula in:
=CONCATENATE("[",SUBSTITUTE(A1," ",""),"] varchar(20),")
then paste that formula all the way down next to your column of column headers
copy the results into SQL Server then add your top line of code
"CREATE TABLE [dbo].[Addresses_Temp] ( "
then add your closing parentheses
What we did is:
we got all the colunn headers from the header ROW and
made them into a column
then removed all spaces (should they be multiword column headers) and
tacked onto the beginning the open bracket "[" and
tacked onto the end "] VARCHAR(20)," (the rest of the line of code)
Related
I need to display the result of MS access Query in DataGridView as below
Select clbal,Drcr from Ledger
Result in one DataGridView Cell As 2000Dr
I Have tried
Select cstr(clbal) & Drcr as cbal from Ledger
but no value is displayed in DataGridView cell
As pointed out, you are quite much free to "concentate" field together, but some caution required if the "NEW" or created colum has the same name as existing columns. As a general rule, you should try and use a different column name.
So, say we have a FirstName column, and LastName column.
But, we want to display as full name.
And for just demonstration, we also was to have a FirstName + "id" as another column (this shows how a number PK can be combined with a string. As pointed out, you don't need (or in fact want to use cstr(), since that looks to be a VBA function anyway, and you can't use that in c#.
So, assuming a access table like this:
So, in above, the "ID" pk column is a number (long number in Access code/VBA
, int in c#)
So, we can in the query builder say write this:
So, when you make a expression in the SQL, give the column a name (AS SomeFieldName).
Also, while Access SQL supports "&" or "+" for concatenation, one should probably get in the habit of using "+", and the reason is that the VAST majority of SQL data engines don't support using & for concatenation, but do support "+".
So, if I run above, then I get this:
Now, say c#, asp.net (or whatever platoform you using with c#),
The we have say this markup:
<asp:GridView ID="GridView1" runat="server" CssClass="table">
</asp:GridView>
And our c# code to fill out the datatable (which then you can send to the above gridView, or your DataGridView.
The code will look like this:
void LoadGrid()
{
string strSQL =
#"SELECT ID, (FirstName + ' ' & LastName) AS FullName,
(FirstName + '[' & ID & ']') AS FirstKey,
HotelName, Description FROM tblHotelsA
ORDER BY HotelName";
DataTable rstData = MyRst(strSQL);
GridView1.DataSource = rstData;
GridView1.DataBind(); // databind only need for web grid
}
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.AccessDB))
{
using (OleDbCommand cmdSQL = new OleDbCommand(strSQL, conn))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
And we get this:
I have code like this for reading an Excel file:
string connStr = "Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=" + path + ";Extended Properties=\"Excel 12.0;HDR=YES\";";
using (OleDbConnection conn = new OleDbConnection(connStr))
{
conn.Open();
DataTable dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
string sheetName = dtSchema.Rows[0].Field("TABLE_NAME");
OleDbDataAdapter sheetAdapter = new OleDbDataAdapter("select * from [" + sheetName + "]", conn);
sheetAdapter.Fill(sheetData);
DataTable dtColumns = conn.GetSchema("Columns", new string[] { null, null, sheetName, null });
...
}
My code needs to use/look at the column headers. The above only works if the column headers are the first row. Sometimes the Excel files that we receive from clients have a couple rows above the column headers with some metadata about the data in the excel. When this happens the column headers will be on something like row 10.
I can open the Excel file and manually delete the extra rows above the column headers and this solves the issue. But we want to remove this manual step.
Is there any easy way to remove/ignore these extra starting rows above the column headers? Or do I have to come up with custom code? The best way I can think of is to turn off HDR and then the first row that has a value in every column is the column header row. Is there an easier way?
I have code that reads from Excel, needs to ignore the first 11 rows in the worksheet, and read from columns A through P for up to 64000 rows.
// Read columns A - P after skipping 11 rows to read the header row
string ExcelDataQuery = string.Concat("SELECT * FROM [", sheetname, "A12:P64012]");
As far as i know (checked that issue in the past) there is no way to select a table with System.Data.OleDb from excel file using SQL query if headers are not placed in row 1. the solution for me (like you do) is to delete all the rows above the header row before querying the worksheet - just opening the workbook with Microsoft.Office.Interop deleting the extra rows, closing it and than querying it.
Excel is a very powerful tool but was never designed to behave like database (SQL \ access file for example).
I try to import an excel in to my DataTable with condition.
example : - The user have my provided excel import template, with the first row 0 as the column header (ItemCode, QTY, SerialNo, Remarks). But due to the user might accidentally insert few unwanted column name in anywhere of my per-ready column or delete one of my column name.
I try to build a code regardless what happen, the system only detect my standard ready column header (ItemCode, QTY, SerialNo, Remarks). And only will add the column still within the excel and ignore those accidentally delete column name.
What is the best way to code the detection of the column name when is exist before allow to import those specific column into dataTable?
Below is my current excel import code (which i try to add the above condition code)
private DataTable ReadExcelToDataTable(string filePath)
{
tableSalesOrder = new DataTable("dtSO");
string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1;TypeGuessRows=0;ImportMixedTypes=Text\"", filePath);
using (OleDbConnection dbConnection = new OleDbConnection(strConn))
{
dbConnection.Open();
DataTable dtExcelSchema = dbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string sSheetName = dtExcelSchema.Rows[0]["TABLE_NAME"].ToString();
dbConnection.Close();
using (OleDbDataAdapter dbAdapter = new OleDbDataAdapter("SELECT DISTINCT * FROM [" + sSheetName + "]", dbConnection)) //rename sheet if required!
dbAdapter.Fill(tableSalesOrder);
}
return tableSalesOrder;
}
I have try to google around, found many hint but still unable to make it work.
Thank you for any advice.
If you just wanted to ignore extra columns, you could use
... new OleDbDataAdapter("Select Distinct ItemCode, QTY, SerialNo, Remarks FROM [" + sSheetName + "] ...
If you need to cope with some of these columns being missing, then it is slightly more complicated. You need to get a list of columns in the excel sheet , eg
DataTable dt = dbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns,
new object[] { null,null, sSheetName, null });
List<string> columnNames = new List<string>();
foreach (DataRow row in dt.Rows)
columnNames.Add(row["Column_name"].ToString());
Then you need to build up your select statement to only include the columns that you want and that exist in the excel sheet.
You could set up your workbooks with named ranges, and extract those. That way it'll work even if they accidentally change the name or insert extra columns. You can select the named range with something like this:
var sql = "SELECT * FROM [Workbook$MyNamedRange]"
using (OleDbDataAdapter dbAdapter = new OleDbDataAdapter(sql, dbConnection));
dbAdapter.Fill(tableSalesOrder);
I solve the issue by using different method, I got the idea from both your guys advise. In fact, after i do some test on my origin code which posted, it only will import according the column name which i define which is ItemCode, Qty, SerialNo & Remakrs at my gridView which my dataTable have assign to it as data source.
The only issue is when one of the column deleted, my import process will be facing problem. This due to the datatable never assign any column name after it created.
I solve it by improve the dataTable set and redefine the column name into It.
if (tableSalesOrder == null)
{
tableSalesOrder = new DataTable("dtSO");
DataColumn colItemCode = new DataColumn("ItemCode",typeof(string));
......
tableSalesOrder.Columns.Add(colItemCode);
......
}
else
{
tableSalesOrder.Clear();
}
Thanks guys for the help. Finally I found where the bugs were.
I am trying to edit DataTable Filled by NpgsqlDataAdapter.
After calling Fill() method, I have only one row in DataTable. Then I changed value of one column only and tried to update as below.
Then I am getting this error:
DBConcurrencyException occured
My code is:
NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT sn,
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
DataTable ds1 = new DataTable();
ds1.Clear();
getAllData.Fill(ds1);
if (ds1.Rows.Count > 0)
{
ds1.Rows[0]["Quantity"] = qty;// calculated value
}
ds1 = ds1.GetChanges();
NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(getAllData);
//getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); };
//cb.SetAllValues = false;
getAllData.DeleteCommand = cb.GetDeleteCommand();
getAllData.InsertCommand = cb.GetInsertCommand();
getAllData.UpdateCommand = cb.GetUpdateCommand();
int x = getAllData.Update(ds1);
if (x > 0)
{
ds1.AcceptChanges();
}
EDIT: I have three fields as primary keys and I am calling only two fields in select statement. Is it reason for DBConcurrency error? But I am able to update the table with same (three fields as primary key) parameters in SQL Server 2005.
UPDATE:
I found the solution and the solution is
I created and used second DataAdapter to update data.
I used getAllData(NpgSqlDataAdapter) To fill table as
NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT
code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
And Also created next Adapter to update as
NpgsqlDataAdapter updateadap= new NpgsqlDataAdapter("SELECT sn, quantity FROM stocktable WHERE Code='" + product + "'
ORDER BY EDate ASC", DatabaseConnectionpg);
NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(updateadap);
//getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); };
//cb.SetAllValues = false;
updateadap.DeleteCommand = cb.GetDeleteCommand();
updateadap.InsertCommand = cb.GetInsertCommand();
updateadap.UpdateCommand = cb.GetUpdateCommand();
int x = updateadap.Update(ds1);
if (x > 0)
{
......
}
I tried alot and found that NpgsqlDataAdapter had problem with Column Code. When i ommited it then it worked. DataType of column code is varchar. I don't know why this was happening. Anybody has idea about it?
This is because DataAdapter uses Optimistic Concurrency by default. This means that if you are trying to update a row that no longer exists in the database or changed, the update from the DataAdapter will fail with the exception above.
Possible scenarios:
Between you selecting the data into the client and sending the
update, another user is deleting or updating this row from his application.
It can be that you are deleting the data from somewhere else in your application.
For example:
You fill the DataTable that will be used for the update.
Deletes the row with Code = 1101 (for example) directly from the database, i.e. you do not use the DataTable here. This is emulating another user deleting the row with Code = 1101 from another application. Or some other part in your code deleting the row with Code = 1101.
Selects out the row with Code = 1101 from the DataTable, this is just to show that it is still there even though you have deleted it from the database itself.
Edits the Quantity column in the row with Code = 1101 in the DataTable. This has to be done, otherwise the call to Update will ignore this row when updating.
Executes the update, this will throw the exception since you are trying to update a row that (no longer) exists in the database.
If you want to implement Last Writer Wins, Add the following code:
cb.ConflictOption = ConflictOption.OverwriteChanges;
Also there is one more possible thing : if you have Decimal/numeric as columns in the DB they may cause this error even though the data looks the same. This is due to a decimal rounding error.
An important note:
You should always use parameterized queries by the way. This kind of string concatenations are open for SQL Injection.
I've been working with a program where I import 2 excel files and those excel files have different columns names.. so it could be the possibility for a user to import the wrong excel file (with other column names) and my problem is that I'm reading the data from excel with OledbDataAdapter so I have to specified the name of each column, so when the user import the wrong file the program stop working (because the program can't find the right columns to get the data).
Okay so my question is, is there a way to check if a column exist in specific excel sheet?
So I'll be able to do something if the column doesn't exist in the file the user imported...
Here's a part of my code:
OleDbCommand command1 = new OleDbCommand(
#"SELECT DISTINCT serie FROM [Sheet1$]
WHERE serie =#MercEnInventario AND serie IS NOT NULL", connection);
command1.Parameters.Add(new OleDbParameter("MercEnInventario", MercInv));
string serieN = Convert.ToString(command1.ExecuteScalar());
readerOle = command1.ExecuteReader();
readerOle.Close();
I got an OleDbException when I try to give value to the string 'serieN' because the column name 'serie' doesn't exists in the excel file the user imported.
If you can help me I'll be so grateful :)
OleDbConnection has GetOleDbSchemaTable command that allows you to retrieve just the list of columns. An example code would be
DataTable myColumns = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, "Sheet1$", null });
This will return a DataTable, populated with column information (names, types and more). You can then loop thru Rows collection examining "COLUMN_NAME" column, something like
foreach (DataRow dtRow in myColumns.Rows)
{
if (dtRow["COLUMN_NAME"].ToString() == "serieN") // Do your stuff here ....
}
How about this:
public bool FieldExists(OleDbConnection connection, string tabName, string fieldName)
{
var adapter = new OleDbDataAdapter(string.Format("SELECT * FROM [{0}]", tabName), connection);
var ds = new DataSet();
adapter.Fill(ds, tabName);
foreach (var item in ds.Tables[tabName].Rows[0].ItemArray)
{
if (item.ToString() == fieldName)
return true;
}
return false;
}