I am writing VBA code for an Excel workbook. I would like to be able to open a connection with an Access database, and then import a txt file (pipe delimited) and create a new table in the database from this txt file. I have searched everywhere but to no avail. I have only been able to find VBA code that will accomplish this from within Access itself, rather than from Excel. Please help! Thank you
Google "Open access database from excel VBA" and you'll find lots of resources. Here's the general idea though:
Dim db As Access.Application
Public Sub OpenDB()
Set db = New Access.Application
db.OpenCurrentDatabase "C:\My Documents\db2.mdb"
db.Application.Visible = True
End Sub
You can also use a data access technology like ODBC or ADODB. I'd look into those if you're planning more extensive functionality. Good luck!
I had to do this exact same problem. You have a large problem presented in a small question here, but here is my solution to the hardest hurdle. You first parse each line of the text file into an array:
Function ParseLineEntry(LineEntry As String) As Variant
'Take a text file string and parse it into individual elements in an array.
Dim NumFields As Integer, LastFieldStart As Integer
Dim LineFieldArray() As Variant
Dim i As Long, j As Long
'Determine how many delimitations there are. My data always had the format
'data1|data2|data3|...|dataN|, so there was always at least one field.
NumFields = 0
For I = 1 To Len(LineEntry)
If Mid(LineEntry, i, 1) = "|" Then NumFields = NumFields + 1
Next i
ReDim LineFieldArray(1 To NumFields)
'Parse out each element from the string and assign it into the appropriate array value
LastFieldStart = 1
For i = 1 to NumFields
For j = LastFieldStart To Len(LineEntry)
If Mid(LineEntry, j , 1) = "|" Then
LineFieldArray(i) = Mid(LineEntry, LastFieldStart, j - LastFieldStart)
LastFieldStart = j + 1
Exit For
End If
Next j
Next i
ParseLineEntry = LineFieldArray
End Function
You then use another routine to add the connection in (I am using ADODB). My format for entries was TableName|Field1Value|Field2Value|...|FieldNValue|:
Dim InsertDataCommand as String
'LineArray = array populated by ParseLineEntry
InsertDataCommand = "INSERT INTO " & LineArray(1) & " VALUES ("
For i = 2 To UBound(LineArray)
If i = UBound(LineArray) Then
InsertDataCommand = InsertDataCommand & "'" & LineArray(i) & "'" & ")"
Else
InsertDataCommand = InsertDataCommand & LineArray(i) & ", "
End If
Next i
Just keep in mind that you will have to build some case handling into this. For example, if you have an empty value (e.g. Val1|Val2||Val4) and it is a string, you can enter "" which will already be in the ParseLineEntry array. However, if you are entering this into a number column it will fail on you, you have to insert "Null" instead inside the string. Also, if you are adding any strings with an apostrophe, you will have to change it to a ''. In sum, I had to go through my lines character by character to find these issues, but the concept is demonstrated.
I built the table programmatically too using the same parsing function, but of this .csv format: TableName|Field1Name|Field1Type|Field1Size|...|.
Again, this is a big problem you are tackling, but I hope this answer helps you with the less straight forward parts.
Related
I have a PDF file that contains a table. I want to use Excel-VBA to search just the first column for an array of values. I have a work around solution at the moment. I converted the PDF to a text file and search it like that. The problem is sometimes these values can be found in multiple columns, and I have no way of telling which one it's in. I ONLY want it if it's in the first column.
When the PDF converts to text, it converts it in a way such that there is an unpredictable amount of lines for each piece of information, so I can't convert it back to a table in an excel sheet based on the number of lines (believe me, I tried). The current method searches each line, and if it sees a match, it checks to see if the two strings are the same length. But like I mentioned earlier, (in a rare case but it does happen) there will be a match in a column that is NOT the column I want to search in. So, I'm wondering, is there a way to extract a single column from a PDF? Or even the entire table as it stands?
Public Sub checkNPCClist()
Dim lines As String
Dim linesArr() As String
Dim line As Variant
Dim these As String
lines = Sheet2.Range("F104").Value & ", " & Sheet2.Range("F105").Value & ", " & Sheet2.Range("F106").Value & ", " & Sheet2.Range("F107").Value
linesArr() = Split(lines, ",")
For Each line In linesArr()
If line <> " " Then
If matchlinename(CStr(line)) = True Then these = these & Trim(CStr(line)) & ", "
End If
Next line
If these <> "" Then
Sheet2.Range("H104").Value = Left(these, Len(these) - 2)
Else: Sheet2.Range("H104").Value = "Nope, none."
End If
End Sub
Function matchlinename(lookfor As String) As Boolean
Dim filename As String
Dim textdata As String
Dim textrow As String
Dim fileno As Integer
Dim temp As String
fileno = FreeFile
filename = "C:\Users\...filepath"
lookfor = Trim(lookfor)
Open filename For Input As #fileno
Do While Not EOF(fileno)
temp = textrow
Line Input #fileno, textrow
If InStr(1, textrow, lookfor, vbTextCompare) Then
If Len(Trim(textrow)) = Len(lookfor) Then
Close #fileno
matchlinename = True
GoTo endthis
End If
End If
'Debug.Print textdata
Loop
Close #fileno
matchlinename = False
endthis:
End Function
I am looking for a way to read from a feed webpage which its structure is something like
A,B,C;E,F,G;....
I want to read this data and put A B and C in the first row and put E F and G in row 2, and etc.
I was looking for a function in VBA, but most of them are for only one determiner.
I also was thinking of using string functions of VBA, which that would be the last resort! Since I must read a long string and then use a cursor (which I don't know if it is like c or not!) that probably leads to unstable performance because first I don't know the volume of data, and second I want to use it in a loop.
Could you please help me with the best solution?
feed = "A,B,C;E,F,G;...."
CSV = Replace( feed, ";", vbNewLine )
TSV = Replace( CSV , ",", vbTab )
Set do = CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}") ' this is a late bound MSForms.DataObject
do.SetText TSV
do.PutInClipboard
ActiveSheet.Paste
Sub Test()
ParseString1 "A,B,C;D,E,F;G,H,I,J,K,L"
ParseString2 "A,B,C;D,E,F;G,H,I,J,K,L"
End Sub
Sub ParseString1(data As String)
Dim clip As MSForms.DataObject
Set clip = New MSForms.DataObject
data = Replace(data, ",", vbTab)
data = Replace(data, ";", vbCrLf)
clip.SetText data
clip.PutInClipboard
Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial
End Sub
Sub ParseString2(data As String)
Dim aColumns, aRows
Dim x As Long
aRows = Split(data, ";")
For x = 0 To UBound(aRows)
aColumns = Split(aRows(x), ",")
Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(1, UBound(aColumns) + 1) = aColumns
Next
End Sub
You'll need to set a reference to the Microsoft Forms 2.0 Object Library if you use ParseString1.
I am trying to use the OpenForm function to filter based on the selections in a multi select list box. what is the correct syntax for this, or is there a better way to go about it? For the sake of example let's say:
List Box has options Ken, Mike, and Sandy.
Car has options Car1, Car2, and Car 3. All cars are owned by 1 or more people from that list box.
If someone from the list box is selected, I would like to open a form containing the cars owned by those people selected.
Thank you!
Ok So I figured out a way to do it:
Create a string to hold a query
Use a For loop to populate the string based on each item selected
Put that string as a filter in the OpenForm command.
Here is the specific code I used to to it. My example in the original post used Cars and People, but my actual context is different: Estimators and Division of Work are the filters. Let me know if you have any questions about it if you're someone who has the same question! Since it might be confusing without knowing more about what exactly I'm trying to accomplish.
Dim strQuery As String
Dim varItem As Variant
'query filtering for estimators and division list box selections
strQuery = ""
If Me.EstimatorList.ItemsSelected.Count + Me.DivisionList.ItemsSelected.Count > 0 Then
For Each varItem In Me.EstimatorList.ItemsSelected
strQuery = strQuery + "[EstimatorID]=" & varItem + 1 & " OR "
Next varItem
If Me.EstimatorList.ItemsSelected.Count > 0 And Me.DivisionList.ItemsSelected.Count > 0 Then
strQuery = Left(strQuery, Len(strQuery) - 4)
strQuery = strQuery + " AND "
End If
For Each varItem In Me.DivisionList.ItemsSelected
strQuery = strQuery + "[DivisionID]=" & varItem + 1 & " OR "
Next varItem
strQuery = Left(strQuery, Len(strQuery) - 4)
End If
Using the JOIN function for cleaner and safer code
When you find yourself repeatedly building incremental SQL strings with delimiters like "," "AND" "OR" it is convenient to centralize the production of array data and then use the VBA Join(array, delimiter) function.
If the interesting keys are in an array, a user selection from a multiselect listbox to build a SQL WHERE fragment for the form filter property could look like this:
Private Sub lbYear_AfterUpdate()
Dim strFilter As String
Dim selction As Variant
selction = ListboxSelectionArray(lbYear, lbYear.BoundColumn)
If Not IsEmpty(selction) Then
strFilter = "[Year] IN (" & Join(selction, ",") & ")"
End If
Me.Filter = strFilter
If Not Me.FilterOn Then Me.FilterOn = True
End Sub
A generic function to pick any column data from selected lisbok rows may look like this:
'Returns array of single column data of selected listbox rows
'Column index 1..n
'If no items selected array will be vbEmpty
Function ListboxSelectionArray(lisbox As ListBox, Optional columnindex As Integer = 1) As Variant
With lisbox
If .ItemsSelected.Count > 0 Then
Dim str() As String: ReDim str(.ItemsSelected.Count - 1)
Dim j As Integer
For j = 0 To .ItemsSelected.Count - 1
str(j) = CStr(.Column(columnindex - 1, .ItemsSelected(j)))
Next
ListboxSelectionArray = str
Else
ListboxSelectionArray = vbEmpty
End If
End With
End Function
A few array builders in the application library and coding can be made look more VB.NET
I'm learning for loop and I cannot get this problem fixed.
The problems are in the following codes.
dim rt as integer = 2
dim i As Integer = 0
dim currentpg as string = "http://homepg.com/"
For i = 0 To rt
currentpg = currentpg & "?pg=" & i
messagebox.show(currentpg)
next
'I hoped to get the following results
http://homepg.com/?pg=0
http://homepg.com/?pg=1
http://homepg.com/?pg=2
'but instead I'm getting this
http://homepg.com/?pg=0
http://homepg.com/?pg=0?pg=0
http://homepg.com/?pg=0?pg=0?pg=0
Please help me
Thank you.
You probably need something like this:
Dim basepg as string = "http://homepg.com/"
For i = 0 To rt
Dim currentpg As String = basepg & "?pg=" & i
messagebox.show(currentpg)
Next
Although a proper approach would be to accumulate results into a List(Of String), and then display in a messagebox once (or a textbox/file, if too many results). You don't want to bug user for every URL (what if there are 100 of them?). They would get tired of clicking OK.
First of all, you went wrong while copying the output of the buggy code. Here is the real one.
http://homepg.com/?pg=0
http://homepg.com/?pg=0?pg=1
http://homepg.com/?pg=0?pg=1?pg=2
It does not work because currentpg should be a constant but it is changed on each iteration.
Do not set, just get.
MessageBox.Show(currentpg & "?pg=" & i)
Or you can use another variable to make it more readable.
Dim newpg As String = currentpg & "?pg=" & i
MessageBox.Show(newpg)
Also, your code is inefficient. I suggest you to change it like this.
Dim iterations As Integer = 2
Dim prefix As String = "http://homepg.com/?pg="
For index As Integer = 0 To iterations
MessageBox.Show(prefix & index)
Next
I need an elegant way using VB.Net to iterate through a range of IP addresses when the input will come to my app as a string in this format:
192.168.100.8-10
This range would include 3 addresses:
192.168.100.8, 192.168.100.9, 192.168.100.10.
I found a solution in C# that uses the IP Address class that I could probably convert to VB but it seemed to be way too much code for what I need to do. I could definitely use a bunch of string parsing functions but I was hoping someone already had a simple way of doing this.
Here is a solution. It would be even easier using generic lists...
Dim arrFinalIpList() As String
Dim strIP As String = "192.168.100.8-10"
Dim arrIP() As String = strIP.Split(".")
Dim strPrefix As String = arrIP(0) & "." & arrIP(1) & "." & arrIP(2) & "."
Dim arrMinAndMax() As String = arrIP(3).Split("-")
Dim intCursor As Integer = 0
For intCursor = CInt(arrMinAndMax(0)) To CInt(arrMinAndMax(1))
If arrFinalIpList Is Nothing Then
ReDim arrFinalIpList(0)
arrFinalIpList(0) = strPrefix & intCursor.ToString()
Else
ReDim Preserve arrFinalIpList(arrFinalIpList.Count)
arrFinalIpList(arrFinalIpList.Count - 1) = strPrefix & intCursor.ToString()
End If
Next