Match data found in a query - vba

I need to create a VBA code that computes whether the data in the query that I have created matches or not. I am finding it difficult to begin to write the code.
what I started doing is the following:
Private Sub Analyse_Click()
Dim row As Long
With Query("qry_test1").Range((qry_test1Range))
For row = 1 To .rows.Count
If .Cells(row, AccountingPeriodCol).Value Like AccountingPeriodCriteria
Debug.Print .Cells(row, ValueCol)
End If
End Sub
its wrong as the error wrong number of arguments or invalid property assignment appears.
Could some please be so kind of explaining the problem please

What you got in your code is Excel-VBA, apart from you replacing Sheets("WorksheetName") with Query("qry_test1").
This won't work. For stuff like that, you want to use SQL.
Read a tutorial on the basic syntax.
Create → Query Design → SQL View.
Write your SQL. Somethin along the lines of
SELECT *
FROM qry_Test
WHERE AccountingPeriod = 'your Criteria'`
should do what you want.
Optionally, wrap that into VBA

Related

Subform issue ms access vba

I am writing because I faced very time consuming issue I have not yet solved. It is connected with ms access query and form data exchange. To put it in a simple way. I have the following form:
Form
I have table with cars and inside it columns in the order as shown in the Q_Cars query. I have also subform which is updated using particular comboboxes (currently two assigned) which are updating query using VBA code (requery option). However it works only if I pick values for both comboboxes only.
Can you help me to find a way to put i a query criteria criterion which for an empty combobox will run query with all available data?
I tried to use e.g. the following structure inside criteria in query form:
IIf( Formularze![Form]![T_id] <>""; «Wyr» Formularze![Form]![T_id] ;>0)
Or other attempts with isempty, isnull function but without success.
Do you know how to solve this issue?
In my version due to language "," is replaced with ";" inside if structure.
Remaining code:
Private Sub btn_clear_Click()
Me.T_brand.Value = ""
Me.T_id.Value = ""
Me.T_color = ""
Me.T_seats = ""
Q_Cars_subform.Requery
End Sub
Private Sub T_brand_AfterUpdate()
Q_Cars_subform.Requery
End Sub
Private Sub T_id_AfterUpdate()
Q_Cars_subform.Requery
End Sub
and table
table
Regards,
Peter
Query code:
SELECT Cars.car_id, Cars.car_brand, Cars.car_color, Cars.car_seats
FROM Cars
WHERE (((Cars.car_id)=IIf(Formularze!Form!T_id<>"","«Wyr» Formularze![Form]![T_id] ",(Cars.car_id)>0)) And ((Cars.car_brand)=Formularze!Form!T_brand));
That IIF contains invalid code.
You can just use a logical OR statement in your WHERE criterium, no need for IIF.
Try the following:
SELECT Cars.car_id, Cars.car_brand, Cars.car_color, Cars.car_seats
FROM Cars
WHERE (Cars.car_id = Formularze![Form]![T_id] OR Nz(Formularze![Form]![T_id]) = "")
AND (Cars.car_brand = Formularze!Form!T_brand OR NZ(Formularze!Form!T_brand) = "");
Note that this will show everything if both are empty, I can adjust it to show nothing in that case if needed.

VBA UDF fails to call Range.Precedents property

I am trying to write a simple UDF, which is supposed to loop through each of the cells of a given_row, and pick up those cells which do not have any precedent ranges, and add up the values.
Here is the code:
Public Function TotalActualDeductions(given_row As Integer) As Integer
Total_Actual_Deduction = 0
For present_column = 4 To 153
Set precedent_range = Nothing
If Cells(2, present_column) = "TDS (Replace computed figure when actually deducted)" Then
On Error Resume Next
Set precedent_range = Cells(given_row, present_column).Precedents
If precedent_range Is Nothing Then
Total_Actual_Deduction = Total_Actual_Deduction + Cells(given_row, present_column)
End If
End If
Next
TotalActualDeductions = Total_Actual_Deduction
End Function
If I try to run it by modifying the top declaration, from:
Public Function TotalActualDeductions(given_row As Integer) As Integer
to:
Public Function TotalActualDeductions()
given_row = 4
then it runs successfully, and as expected. It picks up exactly those cells which match the criteria, and all is good.
However, when I try to run this as a proper UDF from the worksheet, it does not work. Apparently, excel treats those cells which have no precedents, as though they have precedents, when I call the function from the worksheet.
I don't know why this happens, or if the range.precedents property is supposed to behave like this.
How can this be fixed?
After a lot of searching, I encountered this:
When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?
Apparently, "any call to .Precedents in a call stack that includes a UDF gets handled differntly".
So, what I did was use Range.Formula Like "=[a-zA-Z]" , because it satisfied my simple purpose. It is in no way an ideal alternative to the range.precedents property.
Foe a more detailed explanation, please visit that link.

Execute a user-defined function into another cell VBA Excel

I need to automatize a process which execute various (a lot) user-defined function with different input parameters.
I am using the solution of timer API found in I don't want my Excel Add-In to return an array (instead I need a UDF to change other cells) .
My question is the following: "Does anybody can explain to me HOW IT IS WORKING?" If I debug this code in order to understand and change what I need, I simply go crazy.
1) Let say that I am passing to the public function AddTwoNumbers 14 and 45. While inside AddTwoNumber, the Application.Caller and the Application.Caller.Address are chached into a collection (ok, easier than vectors in order not to bother with type). Application.Caller is kind of a structured object where I can find the function called as a string (in this case "my_function"), for example in Application.Caller.Formula.
!!! Nowhere in the collection mCalculatedCells I can find the result 59 stored.
2)Ok, fair enough. Now I pass through the two UDF routines, set the timers, kill the timers.
As soon as I am inside the AfterUDFRoutine2 sub, the mCalculatedCell(1) (the first -- and sole -- item of my collection) has MAGICALLY (??!?!?!!!??) obtained in its Text field exactly the result "59" and apparently the command Set Cell = mCalculatedCells(1) (where on the left I have a Range and on the right I have ... I don't know) is able to put this result "59" into the variable Cell that afterward I can write with the .Offset(0,1) Range property on the cell to the right.
I would like to understand this point because I would like to give MORE task to to inside a single collection or able to wait for the current task to be finished before asking for a new one (otherwise I am over-writing the 59 with the other result). Indeed I read somewhere that all the tasks scheduled with the API setTimer will wait for all the callback to be execute before execute itself (or something like this).
As you can see I am at a loss. Any help would be really really welcomed.
In the following I try to be more specific on what (as a whole)
I am planning to achieved.
To be more specific, I have the function
public function my_function(input1 as string, Field2 as string) as double
/*some code */
end function
I have (let's say) 10 different strings to be given as Field2.
My strategy is as follow:
1)I defined (with a xlw wrapper from a C++ code) the grid of all my input values
2)define as string all the functions "my_function" with the various inputs
3)use the nested API timer as in the link to write my functions IN THE RIGHT CELLS as FORMULAS (not string anymore)
3)use a macro to build the entire worksheet and then retrieve the results.
4)use my xlw wrapper xll to process further my data.
You may wonder WHY should I pass through Excel instead of doing everything in C++. (Sometime I ask myself the same thing...) The prototype my_function that I gave above has inside some Excel Add-In that I need to use and they work only inside Excel.
It is working pretty well IN THE CASE I HAVE ONLY 1 "instance" of my_function to write for the give grid of input. I can even put inside the same worksheet more grids, then use the API trick to write various different my_functions for the different grids and then make a full calculation rebuild of the entire worksheet to obtain the result. It works.
However, as soon as I want to give more tasks inside the same API trick (because for the same grid of input I need more calls to my_function) I am not able to proceed any further.
After Axel Richter's comment I would like to ad some other information
#Axel Richter
Thank you very much for your reply.
Sorry for that, almost surely I wasn't clear with my purposes.
Here I try to sketch an example, I use integer for simplicity and let's say that my_function works pretty much as the SUM function of Excel (even if being an Excel native function I could call SUM directly into VBA but it is for the sake of an example).
If I have these inputs:
input1 = "14.5"
a vector of different values for Field2, for instance (11;0.52;45139)
and then I want to write somewhere my_function (which makes the sum of the two values given as input).
I have to write down in a cell =my_function(14.5;11), in the other =my_function(14.5;0.52) and in a third one =my_function(14.5;45139).
These input changes any time I need to refresh my data, then I cannot use directly a sub (I think) and, in any case, as far as I understand, in writing directly without the trick I linked, I will always obtain strings : something like '=my_function(14.5;0.52). Once evaluated (for example by a full rebuild or going over the written cell and make F2 + return) will give me only the string "=my_function(14.5;0.52)" and not its result.
I tried at the beginning to use an Evaluate method which works well as soon as I write something like 14.5+0.52, but it doesn't work as soon as a function (nor a user-defined function) is used instead.
This is "as far as I can understand". In the case you can enlighten me (and maybe show an easier track to follow), it would be simply GREAT.
So far the comments are correct in that they repeat the simple point that a User-Defined Function called a worksheet can only return a value, and all other actions that might inject values elsewhere into the worksheet calculation tree are forbidden.
That's not the end of the story. You'll notice that there are add-ins, like the Reuters Eikon market data service and Bloomberg for Excel, that provide functions which exist in a single cell but which write blocks of data onto the sheet outside the calling cell.
These functions use the RTD (Real Time Data) API, which is documented on MSDN:
How to create a RTD server for Excel
How to set up and use the RTD function in Excel
You may find this link useful, too:
Excel RTD Servers: Minimal C# Implementation
However, RTD is all about COM servers outside Excel.exe, you have to write them in another language (usually C# or C++), and that isn't the question you asked: you want to do this in VBA.
But I have, at least, made a token effort to give the 'right' answer.
Now for the 'wrong' answer, and actually doing something Microsoft would rather you didn't do. You can't just call a function, call a subroutine or method from the function, and write to the secondary target using the subroutine: Excel will follow the chain and detect that you're injecting values into the sheet calculation, and the write will fail.
You have to insert a break into that chain; and this means using events, or a timer call, or (as in RTD) an external process.
I can suggest two methods that will actually work:
1: Monitor the cell in the Worksheet_Change event:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim strFunc As String strFunc = "NukeThePrimaryTargets" If Left(Target.Formula, Len(strFunc) + 1) = strFunc Then Call NukeTheSecondaryTargets End If End Sub
Alternatively...
2: Use the Timer callback API:
However, I'm not posting code for that: it's complex, clunky, and it takes a lot of testing (so I'd end up posting untested code on StackOverflow). But it does actually work.
I can give you an example of a tested Timer Callback in VBA:
Using the VBA InputBox for passwords and hiding the user's keyboard input with asterisks.
But this is for an unrelated task. Feel free to adapt it if you wish.
Edited with following requirements: It is necessary to run a user defined worksheet function, because there are addins called in this function and those work only within a Excel sheet. The function has to run multiple times with different parameters and its results have to be gotten from the sheet.
So this is my solution now:
Public Function my_function(input1 As Double, input2 As Double) As Double
my_function = input1 + input2
End Function
Private Function getMy_Function_Results(input1 As Double, input2() As Double) As Variant
Dim results() As Double
'set the Formulas
With Worksheets(1)
For i = LBound(input2) To UBound(input2)
strFormula = "=my_function(" & Str(input1) & ", " & Str(input2(i)) & ")"
.Cells(1, i + 1).Formula = strFormula
Next
'get the Results
.Calculate
For i = LBound(input2) To UBound(input2)
ReDim Preserve results(i)
results(i) = .Cells(1, i + 1).Value
Next
End With
getMy_Function_Results = results
End Function
Sub test()
Dim dFieldInput2() As Double
Dim dInput1 As Double
dInput1 = Val(InputBox("Value for input1"))
dInput = 0
iIter = 0
Do
dInput = InputBox("Values for fieldInput2; 0=END")
If Val(dInput) <> 0 Then
ReDim Preserve dFieldInput2(iIter)
dFieldInput2(iIter) = Val(dInput)
iIter = iIter + 1
End If
Loop While dInput <> 0
On Error GoTo noFieldInput2
i = UBound(dFieldInput2)
On Error GoTo 0
vResults = getMy_Function_Results(dInput1, dFieldInput2)
For i = LBound(vResults) To UBound(vResults)
MsgBox vResults(i)
Next
noFieldInput2:
End Sub
The user can input first a value input1 and then input multiple fieldInput2 until he inputs the value 0. Then the results will be calculated and presented.
Greetings
Axel

Can you edit the Value property of a named excel object with VBA code?

ThisWorkbook.Names("numWorkersCompEntries").Value = ThisWorkbook.Names("numWorkersCompEntries").Value + 1
I would like to store an incrementing variable in the name manager rather than storing it somewhere in the spreadsheet so that I can manipulate it by name. The above code seems intuitive to me but I am getting a type mismatch. Any ideas? Thanks for any help you can provide.
--Drake
If you modify your code a bit, you'll see that the values of a single numeric are actually stored as a string, so you're trying to add a string, which Excel isn't happy about. You can try something like this:
Sub test()
Dim namedValue As Variant
namedValue = ThisWorkbook.Names("Foo").Value
ThisWorkbook.Names("Foo").Value = Mid(namedValue, 2, Len(namedValue)) + 1
Debug.Print ThisWorkbook.Names("Foo").Value
End Sub
Which seemed to have the expected results on my test sheet...just make sure you have a named range of "Foo" to test. Obviously tweak to suit your situation, but hopefully it will get you started in the right direction.

Is there any limitation for IF condition while using "OR" in vb?

In my code i want to use if condition. In which i want to use "OR" around 18 times.
Like for e.g.
If a="something" or a="something" or a="something" or.........(up to 18 times)... then
'do nothing
else
'do action
end if
[Note : value of a is changing in For loop every time]
so i just want to ask does there any limitation in IF for using OR in limited times.
OR is there any other better way to do the same.
Thanks
As far as I know, there is no limitation when using OR this way.
Yet, you may consider alternative ways of coding this.
Negating a condition using Not
First, if you do nothing in the first case, then consider using the Not statement:
If Not True Then
'do somethin
'no else
End If
Consider using Select Case
Second, if you are checking the very same variable, you could either consider using a Select Case but it doesn't seem appropriate in your case if you have only one case.
Try to use a search
Eventually, if you are checking strings, you could probably better use a search within an array (with Application.Match if you are within Excel or .Contains) or within a String using Instr.
Using a collection or a dictionary
[EDIT] Another very good way to handle this would be to use the Dictionary Structure of VBA and check if a exists (see MSDN for some information).
This answer is just an elaboration on my comments to JMay, full credit to him. I think the original poster meant to the "Something" in his question differ, with a being the loop variable.
For each a in MyList
Select Case a
Case "something", "something2", "something3", "something4", "something5", _
"something6", "something7", "something8", "something9", "something10", _
"something11", "something12", "something13", "something14", "something15", _
"something16", "something17", "something18"
'DO NOTHING
Case Else
'do-something code goes here
' and here
' and here
' and here
End Select
Next a