I'm struggling with a problem that involves interop and excel.
Basically, I have excel files with columns that contain "headers" and the rows beneath the columns have the data. For example, the column Age will have 12,14,etc underneath it. I am new to Interop and I'm trying to allow the user to enter the name of the column header they wish to extract data from, so if they enter "Age", it'll find age is colum B for example and then extract all the data from the proceeding rows.
I've Googled extensively and haven't found anything solid, all rather context orientated and being new to Interop makes this a little tricky.
What I've got so far:
Public Sub getExcelData(ByVal directory As String)
Dim excelAppFirstFile As Excel.Application = Nothing
excelAppFirstFile = CreateObject("Excel.Application")
Try
excelAppFirstFile.Workbooks.Open(directory)
Dim excelSheet As Excel.Worksheet = excelAppFirstFile.Worksheets(1)
Catch ex As Exception
MsgBox("There was a problem: " + ex.Message)
End Try
End Sub
I know it isn't much but I've gone in circles with ranges,etc and can't figure out how to get where I need to.
EDIT:
I forgot to add that the Column name being searched for is a variable called field which is set at an earlier stage by the user.
If all you want to do is read data in the Excel file, I suggest you to use OleDb instead of interop (which is much faster):
Dim filePath As String = "C:\Book1.xls"
Dim connectionString As String = (Convert.ToString("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=") & filePath) + ";Extended Properties=""Excel 8.0"";"
Dim connection As New OleDbConnection(connectionString)
Dim cmdText As String = "SELECT * FROM [Sheet1$]"
Dim command As New OleDbCommand(cmdText, connection)
command.Connection.Open()
Dim reader As OleDbDataReader = command.ExecuteReader()
If reader.HasRows Then
While reader.Read()
Console.WriteLine("{0}" & vbTab & "{1}", reader(0).ToString(), reader(1).ToString())
End While
End If
Related
I have a vb.net application program that is suppose to query a oracle/labdaq database and load the dataset into a datatable. For some reason the query works fine and there is no exception thrown, however, when I load the data it seems to be missing the first row. I first noticed the issue when I did a query for a single row and it returned zero rows when I checked the datatable's row amount during debugging. I then compared all my data sets to a data miner application straight from the oracle source and i seems to always be missing one, the first, row of data when I use the application.
here is the code... I changed the query string to something else to maintain company privacy
Private Sub CaqOnSQL(strFileDirect As String)
Try
Dim connString As String = ConfigurationManager.ConnectionStrings("CA_Requisition_Attachments.Internal.ConnectionString").ConnectionString
Dim conn As New OracleConnection With {
.ConnectionString = connString
}
Dim strQuerySQL As String = "SELECT * FROM REQUISITIONS " &
"WHERE DATE BETWEEN TO_DATE('12/10/2020','MM/dd/yyyy') AND " &
"TO_DATE('12/14/2020','MM/dd/yyyy') " &
"ORDER BY ID"
conn.Open()
Dim Cmd As New OracleCommand(strQuerySQL, conn) With {
.CommandType = CommandType.Text
}
Dim dr As OracleDataReader = Cmd.ExecuteReader()
dr.read()
Dim dt As New DataTable
dt.TableName = "RESULTS"
dt.Load(dr)
ExcelFileCreation(dt, strFileDirect)
You should remove the line:
dr.read()
The call to Read is what is causing you to skip the first row, when combined with the DataTable Load method.
In addition, I have taken the liberty to make some additional changes to your code for the purposes of Good Practice. When using Database objects like Connection and Command, you should wrap them in Using blocks to ensure the resources are released as soon as possible.
Dim dt As New DataTable()
dt.TableName = "RESULTS"
Using conn As New OracleConnection(connString)
conn.Open()
Dim strQuerySQL As String = "SELECT * FROM REQUISITIONS " &
"WHERE DATE BETWEEN TO_DATE('12/10/2020','MM/dd/yyyy') AND " &
"TO_DATE('12/14/2020','MM/dd/yyyy') " &
"ORDER BY ID"
Using command = New OracleCommand(strQuerySQL , conn)
Using dataReader = command.ExecuteReader()
dt.Load(dataReader)
End Using
End Using
End Using
Note: Be wary of Using blocks when using a DataReaderas you may find the connection is closed when you don't want it to be. In this case, the DataReader is used entirely within this function and is safe to use.
When I try to do an import from an Excel document the comments get truncated. I have checked the usually issue that the Table would be limited but is set as:
Comments ... nvarchar(MAX)
Sample of the code, please note even running the code in Debug mode I can see the parameter is truncated before it even goes to the stored procedure.
Dim excelConnectionString As String = (Convert.ToString("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=") & vFileNameFolder) + "; Extended Properties='Excel 12.0;HDR=YES;IMEX=1;';"
'#### Upload, Rename and save file
'#### Open Excel to Parse here
Dim ds As New DataSet
Dim oleda As New OleDbDataAdapter()
Dim cmdExcel As New OleDbCommand()
'#### End - Open Excel to Parse here
Dim vActionRef As String = ""
Try
Dim excelConnection As New OleDbConnection(excelConnectionString)
With cmdExcel
.CommandText = "Select * from [Portal$A1:BB9999]" 'Names we want to select and the name of the sheet
.CommandType = CommandType.Text
.Connection = excelConnection
End With
excelConnection.Open()
oleda = New OleDbDataAdapter(cmdExcel)
oleda.Fill(ds, "dataExcel")
If ds.Tables("dataExcel").Rows.Count > 0 Then
'#### Stored procedure details
Dim connection As SqlConnection
Dim commandSQL As New SqlCommand
Dim FRAUPRN As String = ""
Dim ConnectionString As String = System.Configuration.ConfigurationManager.ConnectionStrings("SQLLocal").ToString()
'########### End - Stored procedure details
'Set date once
Dim vDate As Date
vDate = DateTime.Now.AddDays(0)
connection = New SqlConnection(ConnectionString)
connection.Open()
'Dims for error handling and checking for invalid characters
Dim iImported As Integer
For j As Integer = 0 To ds.Tables("dataExcel").Rows.Count - 1 ' counted rows so loop through, ignores first row with names in
If (IsDBNull(ds.Tables("dataExcel").Rows(j)("UPRN"))) Then
'skip
Else
iImported = iImported + 1
'Bring the data across, the rows(i)("xxx") must match a name on the Excel sheet but DOES NOT have to be in order
With commandSQL
.Parameters.Clear()
.Connection = connection
.CommandText = "spAddCSVDataLine" 'Stored procedure here
If Trim(ds.Tables("dataExcel").Rows(j)("Comments")) = "0" Then
.Parameters.AddWithValue("Comments", " ")
Else
' .Parameters.AddWithValue("Comments", If(IsDBNull(ds.Tables("dataExcel").Rows(j)("Comments")), "", Trim(ds.Tables("dataExcel").Rows(j)("Comments"))))
Dim vComments As String
vComments = ds.Tables("dataExcel").Rows(j)("Comments")
.Parameters.AddWithValue("Comments", vComments)
Session.Item("Comments") = Session.Item("Comments").ToString & "//" & vComments
End If
I have looked at similar questions such as ADO is truncating Excel data which talks about numerical issues but am struggling to find the reason why I am losing data before I export the data. 'Common sense' says excel is not passing over more than 255 characters but then this is programming!
I've had all sorts of problems with the JET/Ace DB engine truncating and doing other sorry-ass guesses at data type. Check out this Microsoft article that talks a bit about how JET uses only the first 8 records to determine field length (http://support.microsoft.com/kb/189897/en-us). You can edit a registry setting to change how many records it will scan to determine field length, but the results still seem to be hit or miss for folks.
You might also find some luck in creating a dummy record at the top of the excel sheet that contains a comment with the maximum number of characters of any of your comments. Then just delete that one record after it comes through. Again... results seem to be mixed here.
I am trying to convert VBA code to vb.net, im having trouble trying to search the database for a specific value around an if statement. any suggestions would be greatly appriciated.
thedatabase is called confirmation, type is the column and email is the value im looking for. could datasets work?
Function SendEmails() As Boolean
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
Dim intResponse As Integer
Dim confirmation As New ADODB.Recordset
Dim details As New ADODB.Recordset
On Error GoTo Err_Execute
Dim MyConnObj As New ADODB.Connection
Dim cn As New ADODB.Connection()
MyConnObj.Open( _
"Provider = sqloledb;" & _
"Server=myserver;" & _
"Database=Email_Text;" & _
"User Id=bla;" & _
"Password=bla;")
confirmation.Open("Confirmation_list", MyConnObj)
details.Open("MessagesToSend", MyConnObj)
If details.EOF = False Then
confirmation.MoveFirst()
Do While Not confirmation.EOF
If confirmation![Type] = "Email" Then
' Create the Outlook session.
objOutlook = CreateObject("Outlook.Application")
' Create the message.
End IF
If you want really convert your code to NET then I think you should remove the ADODB objects and use the System.Data.SqlClient classes. Of course some things are more difficult now because the ADO.NET really use a detached model to work with databases.
The semi-equivalent of your code using the ADO.NET classes
....
' Use Try/Catch not the On Error Goto....'
Try
Dim conStr = "Server=myserver;Database=Email_Text;User Id=XXXX;Password=XXXXX;"
Using MyConnObj = new SqlConnection(conStr)
' Getting all the details rows and columns, '
' but you should select only the columns needed here....'
Using cmdDetails = new SqlCommand("SELECT * FROM MessagesToSend", MyConnObj)
' You need only the rows with Type=Email, so no need to retrieve all the rows'
Using cmdConfirm = new SqlCommand("SELECT * FROM Confirmation_list " & _
"WHERE [Type] = 'EMail' ", MyConnObj)
MyConnObj.Open
Using da = new SqlDataAdapter(cmdConfirm)
Dim dt = new DataTable()
da.Fill(dt)
Using reader = cmdDetails.ExecuteReader()
While reader.Read()
For Each row in dt.Rows
... ' The Outlook app should be instanced outside the loop'
Next
Loop
End Using
End Using
End Using
End Using
End Using
Catch x As Exception
MessageBox.Show("Error:" & x.Message)
End Try
Possibly the usage of the Type column is causing an issue. You might be able to get this working by doing the following:
confirmation.Fields("Type").Value
instead of
confirmation![Type]
but I would recommend you look into ADO.NET isntead of using ADODB as this is quite old now.
I have two Combo-Boxes like this
I need to create an auto-fill feature for the 1st Combo-Box. It should list the EmployeeID if Search-By Field is specified as Employee-Number. Similarly it should list Employee First Name along with Last Name if the Search-By Field is Employee-Name.
How can I do this? I have no clue, I am doing this for the first time. I am using SQLite, Visual Studio 2010.
Dim mySelectQuery As String = "SELECT " & Search & " FROM EmployeeTable WHERE Status LIKE '" & Status & "'"
Dim myConnString As String = "Data Source=" & Application.StartupPath & "\Database\SimpleDB.db3"
Dim sqConnection As New SQLiteConnection(myConnString)
Dim sqCommand As New SQLiteCommand(mySelectQuery, sqConnection)
sqConnection.Open()
Try
' Always call Read before accessing data.
Dim sqReader As SQLiteDataReader = sqCommand.ExecuteReader()
Dim j As Integer = sqReader.FieldCount
While sqReader.Read()
'''''''''''''''''''''''Here, Don't know how to list the items from the query reult into the combo-box
End While
'Close Reader after use
sqReader.Close()
Catch ex As Exception
'Show Message on Error
MsgBox(ex.ToString)
Finally
'At Last Close the Connection
sqConnection.Close()
End Try
I'm not sure entirely what you are asking but I think this is it.
In the SelectedIndex changed event you would have something similar to the code below. You can add an If statement to check what you are querying for and adjust your query accordingly.
Dim dt as New DataTable
Try
Using sqlConn
sqlConn.Open()
Using cmd As New SqlCommand("your query")
cmd.Connection = sqlConn
cmd.CommandType = CommandType.Text
Dim reader as SqlDataReader = cmd.ExecuteReader()
dt.Load(reader)
End Using
End Using
Catch ex As SqlException
Throw New Exception(ex.Message)
End Try
With yourComboBox
.DataSource = dt
.DataValueField = "columName you want to be the value of the item"
.DataTextField = "columnName of the text you want displayed"
End With
Notice the following properties for the combo-box: AutoCompleteMode, AutoCompleteSource, AutoCompleteCustomSource.
Select the appropriate AutoCompleteMode. See details on the different modes at this link.
For AutoCompleteSource, choose either ListItems (in which case the source will be the items of the ComboBox) or CustomSource. Should you choose CustomSource, set the appropriate source as the value of the ComboBox's AutoCompleteCustomSource property.
This should provide you with enough details to do what you're looking for.
The other requirements you've listed - such as taking the data from an SQLite database or changing between employee name and employee number - won't affect the way you work with the AutoComplete feature.
is there a simple way in vb.net to load an excel file and read it? perhaps there is a way to load the file but have it not be visible to the user?
Alex - here is some old code I dug up to query excel. Pretty basic scenario here. Don't pay attention to the poor error handling and lack of the 'Using' construct.
Dim connString As String = "Provider=Microsoft.Jet.OLEDB.4.0" & _
";Data Source=" & ExcelFile & _
";Extended Properties=Excel 8.0;"
Dim conn As OleDbConnection = Nothing
Dim dt As System.Data.DataTable = Nothing
Dim excelDataSet As New DataSet()
Try
conn = New OleDbConnection(connString)
conn.Open()
dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)
If dt Is Nothing Then
Return Nothing
End If
Dim excelSheets(dt.Rows.Count) As String
Dim i As Integer = 0
For Each row As DataRow In dt.Rows
excelSheets(i) = row("TABLE_NAME").ToString
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
If i = SheetNumber Then
Exit For
End If
Next
Using excelCommand As New OleDbCommand("Select * from [" & excelSheets(SheetNumber - 1) & "]", conn)
Using excelAdapter As New OleDbDataAdapter(excelCommand)
excelAdapter.Fill(excelDataSet)
End Using
End Using
Catch ex As OleDbException
Throw
Catch ex As Exception
Throw
Finally
conn.Close()
If conn IsNot Nothing Then
conn.Dispose()
End If
If dt IsNot Nothing Then
dt.Dispose()
End If
End Try
Return excelDataSet
Work with the Excel Object Model directly from .NET.
You can use ado.net to read from excel spreadsheets via the OLEDB JET 4 provider
This just opens the excel file as a file stream instead of opening the actual excel spreadsheet.
Alternatively you could use com-interop and simply set the application object visible property to false.
See http://www.connectionstrings.com/excel
One gotcha to watch out for when using .net and com interop with any office application is that if you try opening the application as a user who is more of a windows service than an actual human user then you will need to login to windows as that user and open the relevant application as that user so that all the registry entries are correctly updated for certain features of the office application.
If you have a more simple (ie small) excel spreadsheet that does not need to be dynamic, I think you could export it as a comma delimited file and then use a loop and streamreader object to parse each comma seperated value into an array.
Kinda round about though...