The current codes I am working on requires me to rearrange the columns in VBA. It has to arranged according to the header, and the headers are "V-d(1)", "V-g(1)", "I-d(1)", "I-g(1)", and this set repeats for numbers 2, 3, etc etc. (e.g V-d(2), I-g(4)). These data are usually jumbled up and I have to arrange them in ascending numbers.
It does not matter if V-g, V-d, I-d or I-g comes first.
Dim num, numadj As Integer
Dim colu, coladj
Range("A1").Select
Do While Range("A1").Offset(0, i - 1).Value <> ""
colu = ActiveCell.Value
coladj = ActiveCell.Offset(0, 1).Value
num = Left(Right(colu.Text, 2), 1)
numadj = Left(Right(coladj.Text, 2), 1)
If num > numadj Then
colu.EntireColumn.Cut Destination:=Columns("Z:Z")
coladj.EntireColumn.Cut Destination:=colu
Columns("Z:Z").Select.Cut Destination:=coladj
i = i + 1
Else
i = i + 1
End If
Loop
I am very new to VBA so please forgive me for any dumb codes that I have created!!! Thank you in advance everyone!
Consider an SQL and RegEx solution to select columns in a specified arrangement. SQL works in Excel for PC which can access Windows' Jet/ACE SQL Engine to query its own workbook like a database table.
Due to the variable nature of sets ranging 3-10, consider finding the highest number set by extracting the numbers from column headers with RegEx using the defined function, FindHighestNumberSet. Then have RunSQL subroutine call the function to build SQL string dynamically.
Below assumes you have data currently in a tab named DATA with an empty tab named RESULTS which will output query results. Two ADO connection strings are available.
Function (iterating across column headers to extract highest number)
Function FindHighestNumberSet() As Integer
Dim lastcol As Integer, i As Integer
Dim num As Integer: num = 0
Dim regEx As Object
' CONFIGURE REGEX OBJECT
Set regEx = CreateObject("VBScript.RegExp")
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "[^0-9]"
End With
With Worksheets("DATA")
lastcol = .Cells(7, .Columns.Count).End(xlToLeft).Column
For i = 1 To lastcol
' EXTRACT NUMBERS FROM COLUMN HEADERS
num = Application.WorksheetFunction.Max(num, CInt(regEx.Replace(.Cells(1, i), "")))
Next i
End With
FindHighestNumberSet = num
End Function
Macro (main module looping through result of above function)
Sub RunSQL()
On Error GoTo ErrHandle
Dim conn As Object, rst As Object
Dim strConnection As String, strSQL As String
Dim i As Integer
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
' DRIVER AND PROVIDER CONNECTION STRINGS
' strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
' & "DBQ=" & Activeworkbook.FullName & ";"
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source='" & ActiveWorkbook.FullName & "';" _
& "Extended Properties=""Excel 8.0;HDR=YES;"";"
' FIRST THREE SETS
strSQL = " SELECT t.[V-d(1)], t.[I-d(1)], t.[I-g(1)]," _
& " t.[V-d(2)], t.[I-d(2)], t.[I-g(2)]," _
& " t.[V-d(3)], t.[I-d(3)], t.[I-g(3)]"
' VARIABLE 4+ SETS
For i = 4 To FindHighestNumberSet
strSQL = strSQL & ", t.[V-d(" & i & ")], t.[I-d(" & i & ")], t.[I-g(" & i & ")]"
Next i
' FROM CLAUSE
strSQL = strSQL & " FROM [DATA$] t"
' OPEN DB CONNECTION
conn.Open strConnection
rst.Open strSQL, conn
' COLUMN HEADERS
For i = 1 To rst.Fields.Count
Worksheets("RESULTS").Cells(1, i) = rst.Fields(i - 1).Name
Next i
' DATA ROWS
Worksheets("RESULTS").Range("A2").CopyFromRecordset rst
rst.Close: conn.Close
Set rst = Nothing: Set conn = Nothing
MsgBox "Successfully ran SQL query!", vbInformation
Exit Sub
ErrHandle:
Set rst = Nothing: Set conn = Nothing
MsgBox Err.Number & " = " & Err.Description, vbCritical
Exit Sub
End Sub
You can sort vertically by a helper row with something like this (tested):
Sub test() ': Cells.Delete: [b2:d8] = Split("V-d(10) V-d(2) V-d(1)") ' used for testing
Dim r As Range: Set r = ThisWorkbook.Worksheets("Sheet1").UsedRange ' specify the range to be sorted here
r.Rows(2).Insert xlShiftDown ' insert helper row to sort by. (used 2nd row instead 1st so that it is auto included in the range)
r.Rows(2).FormulaR1C1 = "=-RIGHT(R[-1]C,LEN(R[-1]C)-3)" ' to get the numbers from the column header cells above, so adjust if needed
r.Sort r.Rows(2) ' sort vertically by the helper row
r.Rows(2).Delete xlShiftUp ' delete the temp row
End Sub
Related
I have pulled together some code which works, but I must confess to not understanding the nitty gritty of what its doing and I seem to open two lots of connections, which seems slow and messy, one to get the sheetname which I think I need for the SQL call, and the call itself.
I use it as function but have stripped out to a Sub to try and improve it. It gets used a lot pulling in utility data from up to 700 separate files as part of a process, and running across multiple clients. So if it can be streamlined it will cut time down massively.
The file format varies depending on the task:
Alarm Data 51 Columns Wide and either 7 lines or 700 sites *7 lines
Meter Data 50 or 99 Columns Wide with a blank column at 51, 15 lines, or up to 700 * 15 lines
I can't control the file formats/lengths and don't know the sheetname as it can vary by source
Any help tidying it up is massively appreciated.
FootSore
Edit: The files will only ever have one Sheet in them, but name unknown. I only need that sheet.
Function ReadExcelFile(ByRef InputFileArray() As Variant, InputFileName As String, InputFileLocation As String, HeaderYesNo As String)
'Reads Excel File and returns InputFileArray
Dim ReadFileArray() As Variant
Dim connectionString As String
Dim sql As String
Set FSO = CreateObject("scripting.filesystemobject")
If FSO.FileExists(InputFileLocation & InputFileName) = True Then
connectionString = _
"Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & InputFileLocation & InputFileName & """;" & _
"Extended Properties=""Excel 12.0;HDR=" & HeaderYesNo & ";IMEX=1"""
'This assumes the Excel file contains column headers -- HDR=Yes
'Routine to get unknown sheet name
Set conn = CreateObject("ADODB.Connection")
conn.connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & InputFileLocation & InputFileName & """;" & _
"Extended Properties=""Excel 12.0;HDR=Yes"""
conn.Open
Set bs = conn.OpenSchema(20) ' 20 = adSchemaTables
Do Until bs.EOF = True
'Debug.Print bs.Fields!Table_Name.Value
SheetName = bs.Fields!Table_Name.Value
bs.MoveNext
Loop
bs.Close: conn.Close
Set bs = Nothing
Set conn = Nothing
'Get the contents of the Excel via SQL saves opening file
sql = "SELECT * FROM [" + SheetName + "]" '
'Go to the VBE's Tools, References then locate and put a check beside 'Microsoft ActiveX Data Objects 6.1 Library' to include the library in your project.
Dim rs As New ADODB.Recordset
rs.Open sql, connectionString
ReadFileArray() = rs.GetRows 'Puts the data from the recordset into an array
rs.Close
Set rs = Nothing
'Debugging Tool
'Dim row As Variant, column As Variant
'For row = 0 To UBound(TotalFileArray, 2)
' For column = 0 To UBound(InputFileArray, 1)
' Debug.Print InputFileArray(column, row)
' Next
'Next
'Limitations mean the columns and rows are read in wrong order.
'Public Sub to transpose array
TransposeArray ReadFileArray, InputFileArray
Erase ReadFileArray
Else
End If
End Function
You can re-use the one connection and recordset. Note if your input file has multiple sheets and/or named ranges then this just picks the first one listed.
Also - you're not getting field headers in the returned array.
Sub Tester()
Dim arr
arr = ReadExcelFile("LookupTable.xlsx", "C:\Temp\", True)
If Not IsEmpty(arr) Then 'read any data?
Sheet1.Range("A1").Resize(UBound(arr, 1), UBound(arr, 2)).Value = arr
End If
End Sub
Function ReadExcelFile(InputFileName As String, InputFileLocation As String, _
HeaderYesNo As String) As Variant
Dim arr As Variant, SheetName As String
Dim sql As String, conn As Object, rs As Object
'ideally you do this check *before* calling the function though...
If Dir(InputFileLocation & InputFileName, vbNormal) = "" Then
MsgBox "File not found!"
Exit Function
End If
Set conn = CreateObject("ADODB.Connection")
conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=""" & InputFileLocation & InputFileName & """;" & _
"Extended Properties=""Excel 12.0;HDR=" & HeaderYesNo & ";IMEX=1"""
Set rs = conn.OpenSchema(20) ' 20 = adSchemaTables, NOTE: also reads named ranges...
If Not rs.EOF Then SheetName = rs.Fields("Table_Name").Value 'Always only one sheet?
rs.Close
If Len(SheetName) > 0 Then 'got a sheet?
rs.Open "SELECT * FROM [" + SheetName + "]", conn 're-use connection
If Not rs.EOF Then ReadExcelFile = TransposeArray(rs.GetRows())
End If
End Function
Function TransposeArray(arr)
Dim arrout(), r As Long, c As Long
ReDim arrout(LBound(arr, 2) To UBound(arr, 2), LBound(arr, 1) To UBound(arr, 1))
For r = LBound(arr, 1) To UBound(arr, 1)
For c = LBound(arr, 2) To UBound(arr, 2)
arrout(c, r) = arr(r, c)
Next c
Next r
TransposeArray = arrout
End Function
UPDATED QUESTION:
I have Update sheet, this sheet contains unique ID that matched the access database ID, I'm trying to update the fields using excel values in "Update" sheet.
The ID is in the Column A the rest of the fields are stored from Column B to R. I'm trying to achieve the below, As follows:
Update the record(values from Column B to R) if Column A (ID) matched existing Access database ID. Then add text in Column S "Updated"
If the Column A (ID) did not found any match in the existing Access database ID, Then add text in Column S "ID NOT FOUND"
Loop to next value
So far, I have the below Sub for Update and Function for Existing ID (Import_Update Module), but I'm getting this error.
Sub Update_DB()
Dim dbPath As String
Dim lastRow As Long
Dim exportedRowCnt As Long
Dim NotexportedRowCnt As Long
Dim qry As String
Dim ID As String
'add error handling
On Error GoTo exitSub
'Check for data
If Worksheets("Update").Range("A2").Value = "" Then
MsgBox "Add the data that you want to send to MS Access"
Exit Sub
End If
'Variables for file path
dbPath = Worksheets("Home").Range("P4").Value '"W:\Edward\_Connection\Database.accdb" '##> This was wrong before pointing to I3
If Not FileExists(dbPath) Then
MsgBox "The Database file doesn't exist! Kindly correct first"
Exit Sub
End If
'find las last row of data
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim cnx As ADODB.Connection 'dim the ADO collection class
Dim rst As ADODB.Recordset 'dim the ADO recordset class
On Error GoTo errHandler
'Initialise the collection class variable
Set cnx = New ADODB.Connection
'Connection class is equipped with a —method— named Open
cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
'ADO library is equipped with a class named Recordset
Set rst = New ADODB.Recordset 'assign memory to the recordset
'##> ID and SQL Query
ID = Range("A" & lastRow).Value
qry = "SELECT * FROM f_SD WHERE ID = '" & ID & "'"
'ConnectionString Open '—-5 aguments—-
rst.Open qry, ActiveConnection:=cnx, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdTable
'add the values to it
'Wait Cursor
Application.Cursor = xlWait
'Pause Screen Update
Application.ScreenUpdating = False
'##> Set exportedRowCnt to 0 first
UpdatedRowCnt = 0
IDnotFoundRowCnt = 0
If rst.EOF And rst.BOF Then
'Close the recordet and the connection.
rst.Close
cnx.Close
'clear memory
Set rst = Nothing
Set cnx = Nothing
'Enable the screen.
Application.ScreenUpdating = True
'In case of an empty recordset display an error.
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
For nRow = 2 To lastRow
'##> Check if the Row has already been imported?
'##> Let's suppose Data is on Column B to R.
'If it is then continue update records
If IdExists(cnx, Range("A" & nRow).Value) Then
With rst
For nCol = 1 To 18
rst.Fields(Cells(1, nCol).Value2) = Cells(nRow, nCol).Value 'Using the Excel Sheet Column Heading
Next nCol
Range("S" & nRow).Value2 = "Updated"
UpdatedRowCnt = UpdatedRowCnt + 1
rst.Update
End With
Else
'##>Update the Status on Column S when ID NOT FOUND
Range("S" & nRow).Value2 = "ID NOT FOUND"
'Increment exportedRowCnt
IDnotFoundRowCnt = IDnotFoundRowCnt + 1
End If
Next nRow
'close the recordset
rst.Close
' Close the connection
cnx.Close
'clear memory
Set rst = Nothing
Set cnx = Nothing
If UpdatedRowCnt > 0 Or IDnotFoundRowCnt > 0 Then
'communicate with the user
MsgBox UpdatedRowCnt & " Drawing(s) Updated " & vbCrLf & _
IDnotFoundRowCnt & " Drawing(s) IDs Not Found"
End If
'Update the sheet
Application.ScreenUpdating = True
exitSub:
'Restore Default Cursor
Application.Cursor = xlDefault
'Update the sheet
Application.ScreenUpdating = True
Exit Sub
errHandler:
'clear memory
Set rst = Nothing
Set cnx = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure Update_DB"
Resume exitSub
End Sub
Function to Check if the ID Exists
Function IdExists(cnx As ADODB.Connection, sId As String) As Boolean
'Set IdExists as False and change to true if the ID exists already
IdExists = False
'Change the Error handler now
Dim rst As ADODB.Recordset 'dim the ADO recordset class
Dim cmd As ADODB.Command 'dim the ADO command class
On Error GoTo errHandler
'Sql For search
Dim sSql As String
sSql = "SELECT Count(PhoneList.ID) AS IDCnt FROM PhoneList WHERE (PhoneList.ID='" & sId & "')"
'Execute command and collect it into a Recordset
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnx
cmd.CommandText = sSql
'ADO library is equipped with a class named Recordset
Set rst = cmd.Execute 'New ADODB.Recordset 'assign memory to the recordset
'Read First RST
rst.MoveFirst
'If rst returns a value then ID already exists
If rst.Fields(0) > 0 Then
IdExists = True
End If
'close the recordset
rst.Close
'clear memory
Set rst = Nothing
exitFunction:
Exit Function
errHandler:
'clear memory
Set rst = Nothing
MsgBox "Error " & Err.Number & " :" & Err.Description
End Function
My below code is working fine. I tried to address your above three points in a different way.
##########################
IMPORTANT
1) I have removed your other validations; you can add them back.
2) DB path has been hard coded, you can set it to get from a cells again
3) My DB has only two fields (1) ID and (2) UserName; you will have obtain your other variables and update the UPDATE query.
Below is the code which is working fine to meet your all 3 requests...Let me know how it goes...
Tschüss :)
Sub UpdateDb()
'Creating Variable for db connection
Dim sSQL As String
Dim rs As ADODB.Recordset
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\test\db.accdb;"
Dim a, PID
'a is the row counter, as it seems your data rows start from 2 I have set it to 2
a = 2
'Define variable for the values from Column B to R. You can always add the direct ceel reference to the SQL also but it will be messy.
'I have used only one filed as UserName and so one variable in column B, you need to keep adding to below and them to the SQL query for othe variables
Dim NewUserName
'########Strating to read through all the records untill you reach a empty column.
While VBA.Trim(Sheet19.Cells(a, 1)) <> "" ' It's always good to refer to a sheet by it's sheet number, bcos you have the fleibility of changing the display name later.
'Above I have used VBA.Trim to ignore if there are any cells with spaces involved. Also used VBA pre so that code will be supported in many versions of Excel.
'Assigning the ID to a variable to be used in future queries
PID = VBA.Trim(Sheet19.Cells(a, 1))
'SQL to obtain data relevatn to given ID on the column. I have cnsidered this ID as a text
sSQL = "SELECT ID FROM PhoneList WHERE ID='" & PID & "';"
Set rs = New ADODB.Recordset
rs.Open sSQL, cn
If rs.EOF Then
'If the record set is empty
'Updating the sheet with the status
Sheet19.Cells(a, 19) = "ID NOT FOUND"
'Here if you want to add the missing ID that also can be done by adding the query and executing it.
Else
'If the record found
NewUserName = VBA.Trim(Sheet19.Cells(a, 2))
sSQL = "UPDATE PhoneList SET UserName ='" & NewUserName & "' WHERE ID='" & PID & "';"
cn.Execute (sSQL)
'Updating the sheet with the status
Sheet19.Cells(a, 19) = "Updated"
End If
'Add one to move to the next row of the excel sheet
a = a + 1
Wend
cn.Close
Set cn = Nothing
End Sub
You need to put the query inside the loop
Option Explicit
Sub Update_DB_1()
Dim cnx As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim qry As String, id As String, sFilePath As String
Dim lastRow As Long, nRow As Long, nCol As Long, count As Long
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Update")
lastRow = ws.Cells(Rows.count, 1).End(xlUp).Row
sFilePath = wb.Worksheets("Home").Range("P4").Value
cnx.open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & sFilePath
count = 0
For nRow = 2 To lastRow
id = Trim(ws.Cells(nRow, 1))
qry = "SELECT * FROM f_SD WHERE ID = '" & id & "'"
Debug.Print qry
rst.open qry, cnx, adOpenKeyset, adLockOptimistic
If rst.RecordCount > 0 Then
' Update RecordSet using the Column Heading
For nCol = 2 To 9
rst.fields(Cells(1, nCol).Value2) = Cells(nRow, nCol).Value
Next nCol
rst.Update
count = count + 1
ws.Range("S" & nRow).Value2 = "Updated"
Else
ws.Range("S" & nRow).Value2 = "ID NOT FOUND"
End If
rst.Close
Next nRow
cnx.Close
Set rst = Nothing
Set cnx = Nothing
MsgBox count & " records updated", vbInformation
End Sub
I have a recordset object generated by the following code.
Private Sub GetID_Click()
'first find max id on sheet; used for if no ID is found on sheet
Dim myRange As Range
Dim maxIdOnSheet As Long
Dim clientSheet As Worksheet
Set clientSheet = Sheets("Client Codes")
Set myRange = clientSheet.Range("A1:A1048576")
maxIdOnSheet = WorksheetFunction.max(myRange) + 1
'set up connections with Nina's housing database
Dim cmd As New ADODB.Command
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strConn As String
Dim strSQL As String
Dim IDdb As Long
Dim IDwb As Long
'connection string
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\db\path\here\db.accdb; Persist Security Info=False"
'open connection database
conn.Open strConn
'sql statement
strSQL = "SELECT * FROM Clients WHERE (((Clients.FirstName)='" & FirstName.Value & "') AND ((Clients.LastName)='" & LastName.Value & "'));"
'open connection with the recordset
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
'use the late-bound application match method to find out where the firstname and lastname values are in the worksheet, if found
Dim first As Long
Dim last As Long
Dim foundWB As Boolean
Dim foundDB As Boolean
foundWB = False
foundDB = False
Dim base As Long
Dim curRow As Long
base = 1
'First check to make sure if both values are in the worksheet
If Not IsError(Application.Match(FirstName.Value, Range("c" & base & ":c1048576"), False)) And Not IsError((Application.Match(LastName.Value, Range("b" & base & ":b1048576"), False))) Then
'if it is in the worksheet, find where it is
While found = False
first = Application.Match(FirstName.Value, Range("c" & base & ":c1048576"), False)
last = Application.Match(LastName.Value, Range("b" & base & ":b1048576"), False)
If first = last Then
foundWS = True
curRow = curRow + first
IDwb = Cells(curRow, 1)
Else
If first < last Then
base = first + 1
curRow = curRow + first
ElseIf last < first Then
base = last + 1
curRow = curRow + last
End If
End If
Wend
Else
'if its not in the WS, it is now the highest +1
IDwb = WorksheetFunction.max(Range("a1:a1048576")) + 1
End If
'find if its in the database
If rs.EOF Then
'if its not in the database, find the highest number and add 1
rs.Close
strSQL = "SELECT MAX(Clients.[Client ID]) FROM Clients;"
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
IDdb = rs.Fields(0) + 1
MsgBox (rs.Properties.Item("Address"))
Else
'if it is, find the first column
IDdb = rs.Fields(0)
foundDB = True
MsgBox (rs.Properties.Item("Address"))
End If
If foundWB = True Then
ClientID.Value = IDwb
ElseIf foundDB = True Then
ClientID.Value = IDdb
Else
If IDdb > IDwb Then
ClientID.Value = IDdb
ElseIf IDwb > IDdb Then
ClientID.Value = IDwb
Else
ClientID.Value = IDwb
End If
End If
End Sub
I have two data sources - the worksheet this macro is located in Excel, and an Access database. I enter client data, and assign it a specific code. The code does that successfully.
I also want to fill out a userform based on that code which is received. The code above successfully queries the database and can get the client ID. I also want things like address, city, state, zip, household income, that is stored in the DB, from the query.
If I was doing this in strictly Excel, I would use a match statement, and if strictly through Access, a SQL query. I'm trying to run this query on both an Excel worksheet and an Access database at the same time, or in the same code. This requires setting up a recordset object: documentation is found here
http://www.w3schools.com/asp/ado_ref_recordset.asp and here
https://msdn.microsoft.com/en-us/library/ms675841(v=vs.85).aspx.
I know that I can get the information with something like
name = rs.fields(1)
address = rs.fields(4)
city = rs.fields(5)
'...
I'd rather get the index dynamically. If people change the database around I'd like for the formula to be stable.
Lets say if the field "Address" could be index 4, 5, 6, 7, until whenever.
How do I dynamically find the index of a specific field in a recordset object?
So, how do I dynamically find the index of a specific field in a recordset object? Lets say if the field "Address" could be index 4,5,6,7, until whenever.
There isn't a direct property in an ADO recordset to get this, but you can find it by looping through the fields and keeping a tally like I do in this function:
Public Function GetRecordsetFieldIndexFromName(rs As adodb.Recordset, ColumnName As String) As Variant
' Pass in an ADODB recordset and a column name and return the column index.
' Returns index in base 0.
' Ben S. - 11/8/2019
On Error GoTo ErrorHandler
Dim i As Long
If rs Is Nothing Then
' Recordset is not loaded
Else
For i = 0 To rs.Fields.count - 1
'Debug.Print i, rs.Fields(i).Name
If rs.Fields(i).Name = ColumnName Then
GetRecordsetFieldIndexFromName = i
Exit For
End If
Next
End If
Exit_Function:
Exit Function
ErrorHandler:
MsgBox "Error #" & err.Number & " - " & err.Description & vbCrLf & "in procedure GetRecordsetFieldIndexFromName"
GoTo Exit_Function
Resume Next
Resume
End Function
Here is a simple test that you can try in Access.
Public Sub TestADOrs()
' BS 11/8/2019 - Test for GetRecordsetFieldIndexFromName
Dim i As Long
Dim strSQL As String
Dim conn As New adodb.Connection
Dim rs As New adodb.Recordset
' Set an object pointing to the current database connection
Set conn = CurrentProject.Connection
strSQL = "Select Top 1 * From MSysObjects"
rs.Open strSQL, conn, adOpenStatic, adLockOptimistic
Debug.Print GetRecordsetFieldIndexFromName(rs, "Flags") ' This should return 4
Set rs = Nothing
Set conn = Nothing
End Sub
I made similar functions to this that work with List Box and Combo Box controls. They will let you return the index or the value from the control by passing the control and the column/field name.
https://stackoverflow.com/a/58773219/1898524 - Reference List Box Column by Field Name
I have many excel files in many folders and I need to delete the rows from all files where in column for ex. B are words from array:
For ex. my bad words list:
the sun, tree, big car, cup, ....
If A2 column is 'The Sun is the star at the center of the Solar System.' - this row has been deleted.
If in column is 'thesunis the..' - this row has been deleted. But is bad!
And my questions:
How to delete rows with exact words of array element?
How to count array elements?
How to escape single quote in array element (example in code below)
How to open all files from folder "C://folder" and after run code save all?
Here is my code:
Sub code()
Dim MyValue As String
Dim a As Integer
'------------------------------------------------------
ArrayValueToRemove = Array("the sun", "code 'in", "another")
Range("B:B").Select
'------------------------------------------------------
For Each cell In Selection
MyValue = CStr(cell.Value)
For a = 0 To 2
If InStr(1, LCase(MyValue), LCase(ArrayValueToRemove(a))) > 0 Then
cell.EntireRow.Delete
Exit For
End If
Next
Next cell
End Sub
Sub deleteBadWordRows()
Dim currentFile, currentSheet, badWords As Variant, lastRow, i As Integer, baseDirectory As String
'------------------------------------------------------
baseDirectory = "c:\folder\"
badWords = Array("the sun", "code 'in", "another")
'------------------------------------------------------
currentFile = Dir(baseDirectory)
While (currentFile <> "")
Workbooks.Open baseDirectory + currentFile
For Each currentSheet In Workbooks(currentFile).Worksheets
lastRow = currentSheet.Cells(currentSheet.Rows.Count, "B").End(xlUp).Row
For j = 1 To lastRow
For i = 0 To UBound(badWords)
If InStr(1, LCase(CStr(currentSheet.Cells(j, "B").Value)), LCase(badWords(i))) > 0 Then
currentSheet.Rows(j).Delete
j = j - 1
lastRow = lastRow - 1
Exit For
End If
Next
Next
Next
Workbooks(currentFile).Save
Workbooks(currentFile).Close
currentFile = Dir
Wend
End Sub
Consider an SQL solution to query your string searches using the LIKE operator with wildcard, %. Excel for PC can connect to the Jet/ACE SQL Engine (Window .dll files) and query workbooks. Here you avoid the nested looping except for iterating through workbooks.
Below assumes all worksheets are tabular in structure with column headers all beginning at A1. Query results are dumped to a new worksheet where you can delete current worksheet afterwards. Be sure to replace placeholders with actual names, CurrentWorksheet, ColumnA, NewWorksheet:
Sub DeleteSQL()
Dim conn As Object, rst As Object
Dim strConnection As String, strSQL As String
Dim i As Integer
Dim wb As Workbook
Dim dirpath As String: dirpath = "C:\\Folder"
Dim xlfile As Variant: xlfile = Dir(dirpath & "\*.xls*")
Do While (xlfile <> "")
Set wb = Workbooks.Open(dirpath & "\" & xlfile)
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
' WORKBOOK CONNECTION
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source='" & dirpath & "\" & xlfile & "';" _
& "Extended Properties=""Excel 8.0;HDR=YES;"";"
' OPEN DB CONNECTION
conn.Open strConnection
' OPEN RECORDSET
strSQL = " SELECT * FROM [CurrentWorksheet$]" _
& " WHERE [ColumnA] LIKE ""%the sun%"" OR [ColumnA]" _
& " LIKE ""%code 'in%"" OR [ColumnA] LIKE ""%another%"""
rst.Open strSQL, conn
wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count).Name = "NewWorkSheet"
' RESULTSET COLUMNS
For i = 1 To rst.Fields.Count
wb.Worksheets("NewWorkSheet").Cells(1, i) = rst.Fields(i - 1).Name
Next i
' RESULTSET DATA ROWS
wb.Worksheets("NewWorkSheet").Range("A2").CopyFromRecordset rst
wb.Close True
rst.Close: conn.Close
Set rst = Nothing: Set conn = Nothing
xlfile = Dir
Loop
End Sub
I have an Excel worksheet with around 100 cols. Does anyone know of an easy way to write the contents of each column to a csv or txt file?
I don't have Excel in front of me, but I think this code is approximately what you need, give or take some syntax errors. It should write each column into a separate file, with each cell on a different row. It will work for arbitrary column heights, though the number of columns is in a variable (for now).
dim fso as FileSystemObject
dim ts as TextStream
dim i as Integer
dim myCell as Range
set fso = FileSystemObject
for i = 0 to TotalColumnNumber
' last argument, True, says to create the text file if it doesnt exist, which is
' good for us in this case
Set ts = fso.OpenTextFile("column_" & i, ForWriting, True)
' set mycell to the first cell in the ith column
set myCell = SheetName.cells(1,i)
' continue looping down the column until you reach a blank cell
' writing each cell value as you go
do until mycell.value = ""
ts.writeline mycell.value
set myCell = myCell.offset(1,0)
loop
ts.close
next
set ts = nothing
set fso = nothing
Let me know if that helps or not, I can take another look later if you would like
Perhaps
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim i As Integer
''This is not the best way to refer to the workbook
''you want, but it is very conveient for notes
''It is probably best to use the name of the workbook.
strFile = ActiveWorkbook.FullName
''Note that if HDR=No, F1,F2 etc are used for column names,
''if HDR=Yes, the names in the first row of the range
''can be used.
''This is the Jet 4 connection string, you can get more
''here : http://www.connectionstrings.com/excel
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
''WHERE 1=1 = headers only, note hdr=yes above
strSQL = "SELECT * " _
& "FROM [Sheet1$] " _
& "WHERE 1=1"
''Open the recordset for more processing
''Cursor Type: 3, adOpenStatic
''Lock Type: 3, adLockOptimistic
''Not everything can be done with every cirsor type and
''lock type. See http://www.w3schools.com/ado/met_rs_open.asp
rs.Open strSQL, cn, 3, 3
''Output including nulls. Note that this will fail if the file
''exists.
For i = 0 To rs.Fields.Count - 1
strSQL = "SELECT [" & rs.Fields(i).Name & "] " _
& "INTO [Text;HDR=YES;FMT=Delimited;IMEX=2;DATABASE=C:\Docs\]." _
& rs.Fields(i).Name & ".CSV " _
& "FROM [Sheet1$] "
''To skip nulls and empty cells, add a WHERE statement
''& "WHERE Trim([" & rs.Fields(i).Name & "] & '')<>'' "
cn.Execute strSQL
Next
''Tidy up
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
A very quick line to get you started ...
for i = 1 to 100
open "file" & i & ".txt" as #1
for each c in columns(i).cells
print #1, c.value
next c
close #1
next i