import excel data - vb.net

I'm able to import my excel into datagridview successfully but only there is a little problem. There is only one column in my excel file and 10 rows. All 9 rows are in numbers and only the last row is a string.
all 10 show up in my datagridview but the last row is blank.
below is my function to open excel file
Public Sub OpenExcel(ByVal sFileName As String)
Dim ConnectionStringTemplate As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source={0};" & _
"Extended Properties=""Excel 8.0;" & _
"HDR=No;IMEX=1"""
Dim ConnectionString As String = String.Format(ConnectionStringTemplate, sFileName)
Dim sqlSelect As String = "SELECT * FROM [Sheet1$];" 'Where you have a sheet named Sheet1
Dim WorkBook As New DataSet
Dim ExcelAdapter As System.Data.Common.DataAdapter = New System.Data.OleDb.OleDbDataAdapter(sqlSelect, ConnectionString)
ExcelAdapter.Fill(WorkBook)
frmMain.dgvCompose.DataSource = WorkBook.Tables(0)
frmMain.staRecords.Text = "Total Records - " & frmMain.dgvCompose.RowCount
End Sub

You can enumarate datatable's rows with foreach and add all items to array or list.
It is more efficent than giving workbook's table to datasource directly. And if string row is exist, you can see when debugging.

Related

Retrieve column header from specific row in excel using ADO and VB.net

I have an app where a user uploads a spreadsheet and specifies the sheetname and row number for the header row. I need the app to extract the column names from that specified row. I was able to get it to work returning the top row. How would i speficy that the column names i want should be on row(x)
Dim ExcelConn As System.Data.OleDb.OleDbConnection
Dim ExcelTable As DataTable = Nothing
Dim dr As DataRow
Dim sheet_found As Boolean = False
ExcelConn = New system.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & file & ";Extended Properties=Excel 12.0;")
End If
'open the file
ExcelConn.Open()
ExcelTable = ExcelConn.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, New Object() {Nothing, Nothing, Nothing, "Table"})
'make sure there is a matching sheet name
For Each dr In ExcelTable.Rows
If dr("TABLE_NAME").ToString() = sheet & "$" Then
sheet_found = True
Exit For
End If
Next
If sheet_found = False Then
MesgBox("the sheet name specified in the header (" + sheet + ") was not found")
ExcelConn.Close()
Exit Sub
Else
Dim sheet_name As String = Nothing
sheet_name = "[" & sheet & "$]"
Dim cmd1 As New System.Data.OleDb.OleDbCommand("Select * From " & sheet_name, ExcelConn)
Dim da As New OleDbDataAdapter("Select * From " & sheet_name, ExcelConn)
Dim ds As DataSet = New DataSet()
Dim dc As DataColumn
da.Fill(ds)
For Each dc In ds.Tables(0).Columns 'this returns col names fine from first row. how would i tell it to get names from 2nd or 3rd row, etc. The integer var is passed in. i just need to know how to specify that it is row(x)
header_row = LCase(RTrim(header_row + "|" + dc.ColumnName))
Next
MsgBox(header_row)
ExcelConn.Close()
End If
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 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 server or access file for example).
There are some known limitations to use the JET/ACE drivers to access data in Excel sheets, as jonathana has pointed out.
As an alternative, I'd like to offer our Excel ADO.NET Provider. With it, you get all of the SQL access to your Excel data that you're accustomed to from the JET/ACE drivers, but with more flexibility in how that data is arranged in Excel.
In your example, you could submit a query like the following to denote that the headers are placed in row 4:
SELECT * FROM Sheet1#A4:**
Using our provider, your code would look similar to the following:
Dim ExcelConn As System.Data.CData.Excel.ExcelConnection
Dim ExcelTable As DataTable = Nothing
Dim dr As DataRow
Dim sheet_found As Boolean = False
ExcelConn = New System.Data.CData.Excel.ExcelConnection("Excel File=" & file & ";")
'open the file
ExcelConn.Open()
ExcelTable = ExcelConn.GetSchema("Tables")
'make sure there is a matching sheet name
For Each dr In ExcelTable.Rows
If dr("Table_Name").ToString() = sheet Then
sheet_found = True
Exit For
End If
Next
If sheet_found = False Then
MesgBox("the sheet name specified in the header (" + sheet + ") was not found")
ExcelConn.Close()
Exit Sub
Else
Dim sheet_name As String = Nothing
'Here, I assume that header_row indicates the row that contains the headers
sheet_name = "[" & sheet & "#A" & header_row & ":**]"
Dim cmd1 As New System.Data.CData.Excel.ExcelCommand("Select * From " & sheet_name, ExcelConn)
Dim da As New System.Data.CData.Excel.ExcelDataAdapter("Select * From " & sheet_name, ExcelConn)
Dim ds As DataSet = New DataSet()
Dim dc As DataColumn
da.Fill(ds)
For Each dc In ds.Tables(0).Columns
'I wasn't sure what this code was meant to accomplish, but at this point,
'dc.ColumnName contains the column names from header_row
Next
ExcelConn.Close()
End If
We have a blog post on our site with more information on our provider and you can download a free trial from our site as well.

Excel VBA ADO SQL connection error - Could not find the object

I got a brilliant answer to my previous question from #Ryan Wildry but I thought I'd ask a different question regarding the same code: here goes.
Background Info
I have a shared (network/server) Excel template file which is both the input file and the data source (although on different sheets). Let's call that Input.xltm.
The code basically picks up a input in a range on Input Sheet, takes the first two letters and finds the closest code from Code Sheet, then populates a UserForm ListBox with the top five results.
The problem
The problem comes when users set off the UserForm and the error usually returns:
Run-time error '-2147467259'
The Microsoft Access database engine could not find the object 'C:\Users\user.name\Documents\Input1'. Make sure the object exists and that you spell its name and the path name correctly.......etc
I think it may have something to do with the fact Excel puts a number after the filename because it's a template file although I don't actually know!
The code
And here's the code:
Public MyConnection As New ADODB.Connection
Public MyRecordset As New ADODB.Recordset
Private Sub UserForm_Initialize()
Dim ColumnName As String: ColumnName = "[Variant code]"
Dim SearchStr As String: SearchStr = Left(Sheets("Input Sheet").Range("B4").Value2, 2)
Dim dbstring As String
dbstring = ThisWorkbook.FullName
Application.ScreenUpdating = False
If MyConnection.State <> adStateOpen Then
With MyConnection
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbstring & _
";Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1';"
.Open
End With
End If
If MyRecordset.State = adStateOpen Then MyRecordset.Close
MyRecordset.Open "Select top 5 " & ColumnName & " from [Code Sheet$] where " & ColumnName & _
" like '%" & SearchStr & "%'", MyConnection, adOpenForwardOnly, adLockReadOnly
Me.ListBox1.Clear
If Not MyRecordset.EOF Then MyRecordset.MoveFirst
Application.ScreenUpdating = True
Do Until MyRecordset.EOF
Me.ListBox1.AddItem MyRecordset.Fields(0).Value
MyRecordset.MoveNext
Loop
End Sub
I just need everyone who accesses the file through the server to be able to pick up the correct data source (which is only in the next sheet) and populate the ListBox.
I'd be thankful for any suggestions! Thanks
#UPDATE
I have checked, now if you open (and then save) the actual template file so there's no '1' after the file name, then the code works as expected. It's only when the template is opened normally and the number automatically appended that it stops working.
It seems that you do not make early-binding for MyConnection and MyRecordset first.
You can make a late-binding by
step 1.
Change
Public MyConnection As New ADODB.Connection
Public MyRecordset As New ADODB.Recordset
to
Public MyConnection As object
Public MyRecordset As object
.
step 2.
Add
Set MyConnection = createobject("adodb.connection")
Set MyRecordset = createobject("adodb.recordset")
before If MyConnection.State <> adStateOpen Then

Excel Insert Into Access Table from Excel defined Table with a Where Clause

A little stuck. I have a an excel table with lets say the following columns
[Date],[Name],[PostCode],[City]
And an access table with the same column names.
I'm trying to insert the excel data table into the access table but want to apply a WHERE clause so that it ignores dates already in the access table.
I can happily inset all data into the access table but cannot apply a WHERE clause successfully ignore the existing dates. And annoyingly I cant reference the actual table name correct so I am referencing the sheet (but works fine).
This is the code I have so far:
Sub TestInsert()
Dim cnn As ADODB.Connection
Dim dbPath As String
Dim xlPath As String
Dim uSQL As String
dbPath = "C:\Test\TestDB.accdb"
xlPath = "C:\Test\TestXL.xlsm"
'Set Connection string
Set cnn = New Connection
cnnstr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
'Open connection to db
cnn.Open cnnstr
uSQL = "INSERT INTO tbl_ApolloBrochurewareReportTEST " _
& "SELECT * FROM [Excel 12.0;HDR=YES;DATABASE=" & xlPath & "].[Sheet1$]"
cnn.Execute uSQL
cnn.Close
End Sub
Any input or knowledge would be great, thank you.
You should be able to expand the SQL expression:
uSQL = "INSERT INTO tbl_ApolloBrochurewareReportTEST " _
& "SELECT * FROM [Excel 12.0;HDR=YES;DATABASE=" & xlPath & "].[Sheet1$] As T " & _
"WHERE T.Date NOT IN (SELECT [Date] FROM tbl_ApolloBrochurewareReportTEST)"

Getting data from an Excel datatable using OLEDB

I have an excel 2007 xlsm file, where on one of the tabs I have several data tables. Using VB.NET, I'm trying to read one table at a time as a named range like so:
Public Function OpeDataFromRange(ByVal Filename as string, ByVal RangeName As String, ByVal bColumnNames As Boolean) as DataTable
' Returns a DataSet containing information from a named range
' in the passed Excel worksheet
Dim sHDR As String
Dim strConn As String
If bColumnNames Then
sHDR = "Yes"
Else
sHDR = "No"
End If
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Filename & ";Extended Properties=""Excel 12.0 Macro;HDR=" & sHDR & """;"
Dim objConn _
As New System.Data.OleDb.OleDbConnection(strConn)
objConn.Open()
' Create objects ready to grab data
Dim objCmd As New System.Data.OleDb.OleDbCommand( _
"SELECT * FROM [" & RangeName & "]", objConn)
Dim objDA As New System.Data.OleDb.OleDbDataAdapter()
objDA.SelectCommand = objCmd
' Fill DataSet
Dim objDS As New System.Data.DataSet()
objDA.Fill(objDS)
' Clean up and return DataSet
objConn.Close()
return objDS
End Function
But I'm getting the error at Fill command:
The Microsoft Office Access database engine could not find the object 'MyNamedTable1'. Make sure the object exists and that you spell its name and the path name correctly.
I tried to read the entire sheet in the SELECT, and then to fish out my table through objDS.Tables, but then Tables gets loaded with only one table with everything in it.
Any Recommendations?
You cannot use Microsoft.Jet.OLEDB.4.0 with Excel 12.0 you should use Microsoft.ACE.OLEDB.12.0 instead.
Incidentally, you are filling a DataSet but returning a DataTable you need to change one of those.
Personally I prefer to use a DataTable for this but you may prefer a DataSet. If you want to use a DataTable you can...
Dim objDT As New DataTable
objDT.Load(objCmd.ExecuteReader)

Filling DataGrid Columns w/ Excel Data in VB

Alright, I finally got this code to work after hours of toiling:
Dim path As String = OpenFileDialog1.FileName
Dim myDataset As New DataSet()
Dim strConn = New OleDbConnection("Provider=Microsoft.ACE.Oledb.12.0;Data Source=" & path & ";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""")
Dim myData As New OleDb.OleDbDataAdapter("SELECT * FROM [Sheet1$]", strConn)
myData.Fill(myDataset)
DataGridView1.DataSource = myDataset.Tables(0).DefaultView
Now that I figured that out I was going to try and place the data in a specific location. On my application I have a datagridview set up with 4 columns. What I would like to do is put column A of the excel file under the 1st column of the datagridview and column C of the Excel File in the second column of the datagridview.
So replace:
DataGridView1.DataSource = myDataset.Tables(0).DefaultView
with:
DataGridView1.columns(0) = myDataset.Tables(0).columns(0)
DataGridView1.columns(1) = myDataset.Tables(0).columns(2)
Obviously this doesnt work, and something tells me I might need a for loop to import the data, but I have never imported information from an Excel file before and to make it worse I have never worked with datagridviews before so I have no idea how to go about this.
I would like to do something like this if I could:
For x = 1 To xldoc.rows.length - 1
DataGridView1.Item(0, x).Value = CType(xlDoc.Cells(0, x + 1), Excel.Range).Text
Next
This ended up being way easier to import the data. Im posting this in case anyone else comes across this thread.
If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
xLApp = New Excel.Application
xLBook = xLApp.Workbooks.Open(OpenFileDialog1.FileName)
xLSheet = xLBook.Worksheets("Sheet1")
For x = 1 To xLSheet.UsedRange.Rows.Count - 1
DataGridView1.Rows.Add()
DataGridView1.Item(0, x - 1).Value = xLSheet.Cells(1 + x, 1).value
DataGridView1.Item(1, x - 1).Value = xLSheet.Cells(1 + x, xLSheet.UsedRange.Columns.Count).value
Next
End If
Dont even bother with:
Dim myDataset As New DataSet()
Dim strConn = New OleDbConnection("Provider=Microsoft.ACE.Oledb.12.0;Data Source=" & path & ";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""")
Dim myData As New OleDb.OleDbDataAdapter("SELECT * FROM [Sheet1$]", strConn)
Think of it roughly as follows:
Excel Work book = Database
Excel Work sheet = Table
Each Excel column = Table column
Each Excel row = Table row
Excel cell = a particular column value in a particular row
If your Excel has column headers, those are your field names. Now change your SQL query to select the columns you want and bind as usual.