Function PrintTableDefs()
Dim aDB As DAO.Database
Dim aTD As DAO.TableDef
Dim aTableName As String
Dim aForeignTableName As String
Dim aString As String
Dim count As Integer
Set count = 0
Set aDB = CurrentDb()
For Each aTD In aDB.TableDefs
Debug.Print aTD.Name
Debug.Print aTD.Connect
Debug.Print ""
count = count + 1
Next
Debug.Print "There are " & count & "table defs."
End Function
When calling this function I get "Compile Error: Expected: =". I have noticed through other questions it is related to parentheses however being mildly unfamiliar with VBA I'm unsure where my syntax is off.
Remove the set from set count = 0
set is only for assigning object references and an Integer is not an object instance.
Alex pointed out the only issue in your function that could throw a compile error: you don't need a set to initialize your count variable, because it is not an object. The rest is correct and should not throw an error, so it is elsewhere.
However your code shows that you don't really understand what is the difference between a sub and a function and it might be helpful to explain it.
A function returns a value, a sub doesn't. That's what's make them different.
You are not returning any value so you should use a sub.
Although your code works fine, because functions that doesn't return a value are accepted by the VBA compiler, it is semantically incorrect and a bad programming habit.
You can make a proper function out of it by returning the number of tables you found (your count variable)
Sub test()
Debug.Print "There are " & PrintTableDefs() & " table defs."
End Sub
Function PrintTableDefs() As Integer
Dim aDB As DAO.Database
Dim aTD As DAO.TableDef
Dim aTableName As String
Dim aForeignTableName As String
Dim aString As String
Dim count As Integer
count = 0
Set aDB = CurrentDb
For Each aTD In aDB.TableDefs
Debug.Print aTD.Name
Debug.Print aTD.Connect
Debug.Print ""
count = count + 1
Next
PrintTableDefs = count
End Function
And if you don't need anything to be returned, make a sub:
Sub PrintTableDefs()
Dim aDB As DAO.Database
Dim aTD As DAO.TableDef
Dim aTableName As String
Dim aForeignTableName As String
Dim aString As String
Dim count As Integer
count = 0
Set aDB = CurrentDb
For Each aTD In aDB.TableDefs
Debug.Print aTD.Name
Debug.Print aTD.Connect
Debug.Print ""
count = count + 1
Next
Debug.Print "There are " & count & " table defs."
End Sub
Additionally, you don't need () when you assign the CurrentDb object :
Set aDB = CurrentDb
My experience is that when calling a function or subroutine in VBA, enclosing your parameters (or lack thereof) in parentheses will cause this error.
There are two ways I know of to handle this:
Just don't use parentheses and always call the sub or function without them. This is fine if you are going from "PrintTableDefs()" to "PrintTableDefs" but can be problematic if the call is nested in a control structure or as another parameter.
Keep your parentheses, because you like parentheses and they remind you of C based language syntax, which helps you forget you are using the sadness of VBA. In that case, always assign the value of a function to a variable "result = PrintTableDefs()" and always use the Call keyword when invoking subroutines.
As an aside: your function returns no value. You should probably replace it with a subroutine, which is done by just replacing the word "Function" with the word "Sub".
Related
I have this simplified class named clsWarehouseSum.
Option Compare Database
Option Explicit
Private wh_units As Scripting.Dictionary
Public Function availableUnits(warehouse As String) As Long
'Debug.Print wh_units(warehouse)
If wh_units Is Nothing Then Set wh_units = New Scripting.Dictionary
If Not wh_units.Exists(warehouse) Then
Dim SQL As String
Dim RS As DAO.Recordset
SQL = "SELECT sum(units) as tot_units " _
& "FROM warehouse " _
& "WHERE warehouse = '" & warehouse & "' "
Set RS = CurrentDb.OpenRecordset(SQL)
wh_units.Add (warehouse), RS("tot_units")
End If
availableUnits = wh_units(warehouse)
End Function
I try to use it like this:
Sub test()
Dim wh As New clsWarehouseSum
Debug.Print wh.availableUnits("Cohasset")
Debug.Print wh.availableUnits("Cohasset")
End Sub
While the first Debug.Print prints what's expected, the second one gives me an error:
Run time error 3420, Object Invalid or no longer set. When I step through the code, it correctly evaluates both if statements as false. Yet, the last line of the function gives me the error mentioned above. What am I doing wrong?
Why?
Add Debug.Print TypeName(wh_units(warehouse)) before the availableUnits = wh_units(warehouse) line and if it prints anything else than Long to the Immediate window then you might want to cast to Long using CLng while you also have some error handler in place.
Or, you might want to make sure that the line wh_units.Add (warehouse), RS("tot_units") is adding a Long to your dictionary so you should check the type before you add.
As a general rule, when you return a specific data type from a dictionary or collection, you should always have checks in place either when you add the data to the dict/coll or when you return it so that you avoid type incompatibility and runtime errors.
I'm trying to make a prepared query based on the value in a field in my form in libreoffice basic.For this, I created a macro.
But it returns an error on the query line saying
BASIC syntax error.
Unexpected symbol: oInstruction_SQL
Sub concatMotherName
Dim oSourceDonnees As Object
Dim oConnexion As Object
Dim stSql As String
Dim oResultat As Object
oSourceDonnees = thisComponent.Parent.dataSource
oConnexion = oSourceDonnees.getConnection("","")
oInstruction_SQL = oConnexion.createStatement()
Dim valueData As String
Dim dateLabel As String
valueData = ThisComponent.Drawpage.Forms.getByName("Form").getByName("id_mother_label").getCurrentValue()
stSql = "SELECT NOM_MERE FROM ""T_MOTHER"" WHERE ""NUM_MOTHER"" = ?" _
oInstruction_SQL = = oConnection.prepareStatement(stSql)
oInstruction_SQL.setString(1, valueData)
oResultat = oInstruction_SQL.executeQuery(stSql)
If Not IsNull(oResultat) Then
oResultat.Next()
MsgBox oResultat.getString(1)
End If
End Sub
There are two syntax problems. The first is the _ after the query string, which indicates that the next line is a continuation of that one. It's not a continuation, so remove it.
The second error is on the next line: = =.
When these errors are fixed, the code compiles successfully.
I have an MS Access database (I'm not after reasons to not use Access).
I am trying to run a VBA sub to cycle through some queries based on a parameter, which is a query result.
There's a query which sums the value in the table for a column.
I need to return this with a function in VBA using an IF ELSE statement to proceed.
Public dbs As DAO.Database
Sub Main()
Dim SumCheck As Double
Set dbs = CurrentDb
GoTo LoopCheck
LoopCheck:
SumCheck = SOSum(dbs)
If SumCheck = 0 Then
GoTo EndPart
Else
GoTo STPTGet
End If
The code doesn't proceed past here, instead when I step into the code it stops here at this function and gives the error "Expected Function or Value"
Public Function SOSum(db As DAO.Database) As Double
Dim sumg As Double
Set db = dbs
Set sumg = db.Execute("LoopCheck")
Set db = Nothing
Set SOSum = sum
End Function
The loop check query is simple
SELECT SUM(Qty)
FROM SO;
The query works in Access, it should just check if it's 0 or not.
This is my first post, so excuse any incorrect formatting or obviously missing information. Any help is greatly appreciated.
Thank you
There are a few issues with your code.
First, it looks like you have dbs as a public Database object. Because of this, you don't need to pass it around to your function. You can just use it once it has been set.
Next, the db.execute method will only run action queries (like INSERT, UPDATE, DELETE...) and it doesn't return anything. You'll need to use a recordset to get at the results of your query.
Lastly, your function returns a Double, so you shouldn't be using the Set keyword to return the value.
Put all together we have this:
A Database object Global Declaration:
Public dbs as DAO.Database
A MAIN Sub (only partial was given in the question):
Sub Main()
Dim SumCheck As Double
Set dbs = CurrentDb
'...
SumCheck = SOSum
'...
And your SOSum Function:
Public Function SOSum() As Double
Dim sum As Double
Dim rs As DAO.Recordset
Set rs= dbs.OpenRecordset("LoopCheck")
sum = rs(0).Value
Set rs = nothing
SOSum = sum
End Function
Objective: I'm building VBA code to filter through an address table SunstarAccountsInWebir_SarahTest. I want to loop through first and see if the address is "valid".
If it is not valid – export to different table.
If it is valid – it enters another nested if/then within "valid" address rows:
If their ID, external_nmad_id matches the ID of the second table 1042s_FinalOutput_7, I want to update one of the columns in the second table box13c_Address.
If it doesn't match an ID of the second table – it will be exported to a different table.
My problem is when I run my code it is returning
Run-Time error 3078: cannot find table or query
(it's breaking at the line where I compare the value of the cell (as string) against the DCount of table 2). If I remove the quotes around it I get a different error:
Type mismatch against the DCount
I feel like I'm missing something simple but can't tell what. How can I get my code to match a string value called in !external_nmad_id against the rest of the table called in my string? DCount("[ID]", StrSQL1)
Public Sub EditFinalOutput2()
'set variables
Dim i As Long
Dim qs As DAO.Recordset
Dim ss As DAO.Recordset
Dim StrSQL1 As DAO.Recordset
Dim IRSfileFormatKey As String
Dim external_nmad_id As String
Dim nmad_address_1 As String
Dim nmad_address_2 As String
Dim nmad_address_3 As String
Dim mytestwrite As String
'open reference set
Set db = CurrentDb
Set qs = db.OpenRecordset("SunstarAccountsInWebir_SarahTest")
'Set ss = db.OpenRecordset("1042s_FinalOutput_7")
'Set StrSQL1 = db.OpenRecordset("SELECT RIGHT(IRSfileFormatKey, 10) As ID
'FROM 1042s_FinalOutput_7;")
With qs.Fields
intCount = qs.RecordCount - 1
For i = 0 To intCount
If (IsNull(!nmad_address_1) Or (!nmad_address_1 = !nmad_city) Or (!nmad_address_1 = !Webir_Country) And IsNull(!nmad_address_2) Or (!nmad_address_2 = !nmad_city) Or (!nmad_address_2 = !Webir_Country) And IsNull(!nmad_address_3) Or (!nmad_address_3 = !nmad_city) Or (!nmad_address_3 = !Webir_Country)) Then
DoCmd.RunSQL "INSERT INTO Addresses_ToBeReviewed SELECT SunstarAccountsInWebir_SarahTest.* FROM SunstarAccountsInWebir_SarahTest WHERE (((SunstarAccountsInWebir_SarahTest.external_nmad_id)='" & qs!external_nmad_id & "'));"
Else:
Set ss = db.OpenRecordset("1042s_FinalOutput_7")
Set StrSQL1 = db.OpenRecordset("SELECT RIGHT(IRSfileFormatKey, 10) As ID FROM 1042s_FinalOutput_7;")
If !external_nmad_id = DCount("[ID]", StrSQL1) Then
ss.Edit
ss.Fields("box13c_Address") = qs.Fields("nmad_address_1") & qs.Fields("nmad_address_2") & qs.Fields("nmad_address_3")
ss.Update
Else: DoCmd.SetWarnings False
DoCmd.RunSQL "INSERT INTO Addresses_NotUsed SELECT SunstarAccountsInWebir_SarahTest.* FROM SunstarAccountsInWebir_SarahTest WHERE (((SunstarAccountsInWebir_SarahTest.external_nmad_id)='" & qs!external_nmad_id & "'));"
DoCmd.SetWarnings True
End If
End If
qs.MoveNext
Next i
End With
'close reference set
qs.Close
Set qs = Nothing
ss.Close
Set ss = Nothing
End Sub
The issue is that the DCount function cannot operate directly against a Recordset.
You are declaring StrSQL1 as a RecordSet object and setting it to a RecordSet based on your Select statement.
Set StrSQL1 = db.OpenRecordset("SELECT RIGHT(IRSfileFormatKey, 10) As ID FROM 1042s_FinalOutput_7;")
You are then trying to pass this RecordSet to the DCount function which cannot accept a RecordSet object as the Domain parameter. As you can see in MSDN the DCount function requires a String parameter in the second position to define the "query" that you wish to "Count". Hence the 3078 error. When you remove the quotes around [ID] in your DCount line, you get Type Mismatch as a compile error because [ID] is not a String or String variable.
After you resolve that, you might want to reconsider your If statement. You haven't provided a sample of what kind of value !external_nmad_id will contain, other than the fact that it is a String value. The DCount function is going to return the number of rows found in the Domain (query) that you told it to count, so it appears you will be comparing a string (which may possibly contain alpha characters) to a number. Access will implicitly convert the DCount numeric result to a String for the sake of the comparison, but if your !external_nmad_id String is truly 10 characters or contains alpha characters, they will never match.
You cannot use a VBA recordset inside a domain aggregate like DCount as a string literal is required for table/query name argument. Simply save your query and then reference it by name in DCount.
SQL (save as query)
SELECT RIGHT(IRSfileFormatKey, 10) As ID FROM 1042s_FinalOutput_7;
VBA
If !external_nmad_id = DCount("[ID]", "mySavedQuery") Then
...
End If
Context: I am writing a function which returns words/numbers present in a string which are enclosed by parenthesis.
Example: Calling ExtractParenthesis("This {should} work. But {doesnt}.") should return a collection containing two items, should and doesnt.
Error: The error I receive from the code below is
Run-time error '450': Wrong number of arguments or invalid property
assignment
It doesn't appear on a particular line and I just receive an error message with "OK" and "Help" as options.
Code:
Public Function ExtractParenthesis(strText As String) As Collection
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As New Collection
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
For i = 0 To (Matches.count - 1)
Output.Add Matches(i).submatches(0)
Next i
Set ExtractParenthesis = Output
End Function
It works exactly the way you want it for me:
Option Explicit
Public Sub TestMe()
Dim myColl As New Collection
Set myColl = ExtractParenthesis("This {should} work. But {doesnt}.")
Debug.Print myColl(1)
Debug.Print myColl(2)
End Sub
Public Function ExtractParenthesis(strText As String) As Collection
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As New Collection
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
For i = 0 To (Matches.Count - 1)
Output.Add Matches(i).submatches(0)
Next i
Set ExtractParenthesis = Output
End Function
I receive "should" and "doesnt" on the immediate window (Ctrl+G). Probably you are not aware that you are returning a collection. It should be used with the Set keyword.
To run it from the immediate window, try like this:
?ExtractParenthesis("This {should} work. But {doesnt}.")(1)
?ExtractParenthesis("This {should} work. But {doesnt}.")(2)
From what I understand of your comment to Vityatas answer you mean you want to run it as a worksheet function - running it directly
The changes I've made to your code will let you use it as a function:
In A1:B1 this will work: {=ExtractParenthesis("This {should} work. But {doesnt}.")}
In A1:A2 use it like this: {=TRANSPOSE(ExtractParenthesis("This {should} work. But {doesnt}."))}
NB: The curly brackets are added by Excel when you enter the formula using Ctrl+Shift+Enter rather than Enter on its own.
The one problem with the code is that you must select the correct number of cells first - if it should return three words, but you've only selected two then you'll only see the first two.
Public Function ExtractParenthesis(strText As String) As Variant
Dim i As Long
Dim RegExp As Object
Dim Matches As Object
Dim Output As Variant
Set Output = Nothing
Set RegExp = CreateObject("vbscript.regexp")
RegExp.Pattern = "{(.*?)}"
RegExp.Global = True
Set Matches = RegExp.Execute(strText)
ReDim Output(1 To Matches.Count)
For i = 1 To (Matches.Count)
Output(i) = Matches(i - 1).submatches(0)
Next i
ExtractParenthesis = Output
End Function