Dealing with Empty Cells in VBA for Access - vba

I have the following code which is supposed to step through an array of fields and create two new arrays to add to a new recordset:
For Each Field In SDSRecordsets(i)
Debug.Print (j)
Debug.Print (Field.Value)
fieldNames(j) = Field.Name
If Field.Value = Null Then
values(j) = ""
Else
values(j) = Field.Value
End If
j = j + 1
Next
The first time this loop runs, the Debug.Print lines print out 0 and then the string value in the first cell as it should. It then runs through the rest of it with no problems. The second time, it tries to add an empty cell. The first Debug.Print prints out 1, as it should, and the second prints out Null, also doing as it should. However, I then get a compile error on the line:
values(j) = Field.Value
Can anyone explain why it is reaching this line, because the way I see it, the If statement must be evaluating Null = Null as false for this to happen.
I've also tried doing this with:
If Not IsEmpty(Field.Value) Then
But that doesn't work either.

Use the Nz function:
For Each Field In SDSRecordsets(i)
Debug.Print (j)
Debug.Print (Field.Value)
fieldNames(j) = Field.Name
values(j) = nz(Field.Value,"")
j = j + 1
Next
Also you can use isnull([expr]) function, the direct comparison with null will not work

Related

VBA Compile error inside if statement

If IsArray(payCsv(pay_id)) = False Then
'create tempArray
lc = 0
Debug.Print "create array"
End If
If IsArray(payCsv(pay_id)) = True Then
Debug.Print " array exists, we should be able to get ubound"
lc = UBound(payCsv(0)) - LBound(payCsv(0))
l = l + 1
End If
I am using the above code to determine whether I can use Ubound on my 2D array (i.e. if the 2nd dimension is created, get length (ubound - lbound).
However, I am getting a compile error, even though condition 2 is false, it does not recognise that the code will not be relevant.
I am testing one array and the result is if I comment out "lc = UBound(payCsv(0)) - LBound(payCsv(0))" is "create array".
If I leave this line in there, I get the error "compile error - expected array"
Is this a bug in VBA?
If you want to access the UBound of the 2nd dimension of an array, the format goes like this:
UBound(payCSV, 2)
The MSDN page on this function may be helpful.
When you access payCSV(0) as you currently are, the code assumes that you want the 1st element within the 1st dimension of the payCSV array.
Perhaps you might want to try this?
If IsArray(payCsv(pay_id)) = False Then
'create tempArray
lc = 0
Debug.Print "create array"
Else
Debug.Print " array exists, we should be able to get ubound"
lc = UBound(payCsv, 2) - LBound(payCsv, 2)
l = l + 1
End If

add names of two variables and make a new dynamic variable

I am writing a code where I have a for loop in which I give a variable (named VType ) some value. For loop goes for a range of i variables. Now I want to make a new variable by concatenating names of both variables. for example if i = 1 then I want to make variable VType1. Here is my piece of code.
nrec = Split(Split(ie.document.body.innerHTML, "Found <strong>")(1), "</strong> records")(0)
If nrec = 1 Then
lnk.Click
Else
For j = 1 To nrec
link.Click
Do While ie.readyState <> 4: Wait 5: Loop
Application.Wait (Now + TimeValue("0:00:01"))
'VType , j = GetType
'Application.Wait (Now + TimeValue("0:00:01"))
IMO , j = GetValue("IMO:")
'MMSI = GetValue("MMSI:")
YBuilt , j = GetValue("Year Built:")
Flag , j = GetValue("Flag:")
DWT , j = GetValue("Deadweight:")
Next j
num = "1 - " & IMO1
For i = 2 To nrec
num = num & vbCrLf & i & "abc"
Next I
fin = InputBox(num, nrec & " records found for a. please select right one.")
Exit For
End If
There is not a way to directly do what you're specifically requesting. However, you can use arrays to get a similar outcome. Arrays are a not a topic that can be explained in a single posted answer, but if you do a little research you can probably figure out how the below might be useful...
Dim VTtyp(0 to i) as string
'while Looping...
Vtype(i) = "Whatever you want stored in this round of i"
When your code completes, you'll have all fields saved as variables that can be called from this array. An example is if you wanted to call the one that was tied to the number "2" you could type: Vtype(2) and it would call the text from the 2 iteration.
Again this example is extremely simplified and there are things to consider such as dim size, changing the dim, preserving the array, etc. and that is something you'll have to research further. However bottom line is, "there is not a way to do what you're specifically trying to do."
You can achieve this using Dictionary objects concept. Go through the below link to know more about dictionary objects.
https://www.tutorialspoint.com/vbscript/vbscript_dictionary_objects.htm

My script to compare two excel files is not working

So I am writing a script to compare two excel files.
I'm using a For loop in the first workbook to get the references I want to find in the second workbook (6450 rows long so that no For loop, way to slow)
I have been looking for some way to use the VLOOKUP thing but i could not make it work Here is the code :
For i = 7 to numLines ''numLines is the number of used lines of the first workbook
If '''test to get out of the LOOP
objExcel.Workbooks(Str1).Sheets(1).Range("D"&i)="" AND objExcel.Workbooks(Str1).Sheets(1).Range("H"&i)="" AND objExcel.Workbooks(Str1).Sheets(1).Range("L"&i)="" Then
i = numLines
Else '' here i get the reference (the 6 first digits of the first workbook and I try to find it in the second)
If objExcel.Workbooks(Str1).Sheets(1).Range("D"&i)<>"" Then
Reference = Mid(objExcel.Workbooks(Str1).Sheets(1).Range("D"&i),1,6)
Set table_lookup = objExcel.Workbooks(Str1).Sheets(1).Range( "C1:C" & numLines2 )
cell = objExcel.Workbooks(Str2).WorksheetFunction.vlookup(Reference, table_lookup, 0, False)
MsgBox cell.row
MsgBox cell.column
End If
End If
Next
You have to switch to the "find" method instead of the vlookup that does not seem to work on vba
For i = 7 to numLines
If objExcel.Workbooks(Str1).Sheets(1).Range("D"&i)="" AND objExcel.Workbooks(Str1).Sheets(1).Range("H"&i)="" AND objExcel.Workbooks(Str1).Sheets(1).Range("L"&i)="" Then
i = numLines
Else
If objExcel.Workbooks(Str1).Sheets(1).Range("D"&i)<>"" Then
Reference = Mid(objExcel.Workbooks(Str1).Sheets(1).Range("D"&i),1,6)
Set r = objExcel.Workbooks(Str2).Sheets(1).Range( "C1:C" & numLines2 )
Set matched = r.Find(Reference)
If Not r.Find(Reference) Is Nothing Then
objExcel.Workbooks(Str1).Sheets(1).Range("R"&i).Value = matched.Offset(0,0).Value
objExcel.Workbooks(Str1).Sheets(1).Range("S"&i).Value = matched.Offset(0,1).Value
objExcel.Workbooks(Str1).Sheets(1).Range("T"&i).Value = matched.Offset(0,2).Value
objExcel.Workbooks(Str1).Sheets(1).Range("U"&i).Value = matched.Offset(0,3).Value
objExcel.Workbooks(Str1).Sheets(1).Range("V"&i).Value = matched.Offset(0,6).Value
End If
End If
End If
Next

Inserting row second time in a loop gives me error, I need to stop macro, save document and restart it to insert the next

I have a VBA macro in excel that are searching for a value in a column and when it is found, it should insert a new, empty row and then continue to search for the next place to insert a new row.
It searches the cells in a column in a loop, it finds the value it's supposed to find and a new row is inserted. The loop resets and it searches the column again for a new value. However, when it finds this value, it does not give me a new row. An "out of memory" message pops up and the macro stops. At that time, I can't manually insert rows either untill I save my document. If I save it, I can re-run my macro and it runs one time without issues and then I get the same result.
I have tried all combinations in the recalculation-settings, I think. I have converted the whole code from using .Select, .Offset etc to use Cells() but the problem is the same. Only differense is that it runs a bit faster now.
This is a sample of the code giving me this issue:
Do While True
currentRow = 1
stringComparer = "PRM_" & prmNumber
Do While True
currentString = Cells(currentRow, parameterColumn)
If StrComp(currentString, stringComparer) = 0 Then
Cells(currentRow, parameterColumn).EntireRow.Insert
Exit Do
End If
currentRow = currentRow + 1
Loop
prmNumber = prmNumber + 1
Loop
Dim parameterColumn As Integer
Dim prmNumber As Integer
Dim Match As Boolean
Match = False
parameterColumn = 1
currentRow = 1
currentString = Cells(currentRow, parameterColumn)
' loop until you reach the end of the data
Do While currentString <> ""
'for each row, check for each of the parameters (I wasnt sure how many you have)
For prmNumber = 1 To 10
If StrComp(currentString, "PRM_" & CStr(prmNumber)) = 0 Then
Match = True
End If
Next
' if there is a match, insert a row and add 2 to the current row (to include the inserted row)
If Match Then
Cells(currentRow, parameterColumn).EntireRow.Insert
currentRow = currentRow + 2
Else
' if there isnt a match, only add 1
currentRow = currentRow + 1
End If
Match = False
currentString = Cells(currentRow, parameterColumn)
Loop

Keeping a count in a dictionary, bad result when running the code, good result adding inspections

Weird problem. Stepping through the code with inspections gives me correct answers. Just running it doesn't.
This program loops through each cell in a column, searching for a regex match. When it finds something, checks in a adjacent column to which group it belongs and keeps a count in a dictonary. Ex: Group3:7, Group5: 2, Group3:8
Just stepping through the code gives me incorrect results at the end, but adding and inspection for each known item in the dictionary does the trick. Using Debug.Print for each Dictionary(key) to check how many items I got in each loop also gives me a good output.
Correct // What really hapens after running the code
Group1:23 // Group1:23
Group3:21 // Group3:22
Group6:2 // Group6:2
Group7:3 // Group7:6
Group9:8 // Group9:8
Group11:1 // Group11:12
Group12:2 // Group12:21
Sub Proce()
Dim regEx As New VBScript_RegExp_55.RegExp
Dim matches
Dim Rango, RangoJulio, RangoAgosto As String
Dim DictContador As New Scripting.Dictionary
Dim j As Integer
Dim conteo As Integer
Dim Especialidad As String
regEx.Pattern = "cop|col"
regEx.Global = False 'True matches all occurances, False matches the first occurance
regEx.IgnoreCase = True
i = 3
conteo = 1
RangoJulio = "L3:L283"
RangoAgosto = "L3:L315"
Julio = Excel.ActiveWorkbook.Sheets("Julio")
Rango = RangoJulio
Julio.Activate
For Each celda In Julio.Range(Rango)
If regEx.Test(celda.Value) Then
Set matches = regEx.Execute(celda.Value)
For Each Match In matches
j = 13 'column M
Especialidad = Julio.Cells(i, j).Value
If (Not DictContador.Exists(Especialidad)) Then
Call DictContador.Add(Especialidad, conteo)
GoTo ContinueLoop
End If
conteo = DictContador(Especialidad)
conteo = CInt(conteo) + 1
DictContador(Especialidad) = conteo
Next
End If
ContinueLoop:
i = i + 1
'Debug.Print DictContador(key1)
'Debug.Print DictContador(key2)
'etc
Next
'Finally, write the results in another sheet.
End Sub
It's like VBA saying "I'm going to dupe you if I got a chance"
Thanks
Seems like your main loop can be reduced to this:
For Each celda In Julio.Range(Rango)
If regEx.Test(celda.Value) Then
Especialidad = celda.EntireRow.Cells(13).Value
'make sure the key exists: set initial count=0
If (Not DictContador.Exists(Especialidad)) Then _
DictContador.Add Especialidad, 0
'increment the count
DictContador(Especialidad) = DictContador(Especialidad) +1
End If
Next
You're getting different results stepping through the code because there's a bug/feature with dictionaries that if you inspect items using the watch or immediate window the items will be created if they don't already exist.
To see this put a break point at the first line under the variable declarations, press F5 to run to the break point, then in the immediate window type set DictContador = new Dictionary so the dictionary is initialised empty and add a watch for DictContador("a"). You will see "a" added as an item in the locals window.
Collections offer an alternative method that don't have this issue, they also show values rather than keys which may be more useful for debugging. On the other hand an Exists method is lacking so you would either need to add on error resume next and test for errors instead or add a custom collection class with an exists method added. There are trade-offs with both approaches.