vba- If else statement within a for loop - ms-access

I'd like to add the following that deletes row that contains 0
If Cells(intFile, "CU") = "0" Then
Sheet1.Rows(r).EntireRow.Delete
End If
to my code below.
If CDate(rst(3)) >= Date Then
For intCount = 0 To rst.Fields.Count - 1
strHold = strHold & rst(intCount).Value & "|"
Currently on 'Cells' ElseIf Cells(intFile, "CU") = "0" Then
I'm getting compile error: sub or function not defined.
what should i put instead of Cells?
My reference: https://msdn.microsoft.com/en-us/library/752y8abs.aspx

The issue here is that there are many "flavours" of Visual Basic, and they aren't interchangeable.
Your application is running in MSAccess, and it will have certain objects, functions, etc, that are specifically applicable to that environment. The Cells object is something that is specifically applicable to the MS Excel environment and therefore Access VBA has no understanding of what a Cells object is.
(And the documentation you referred to is regarding the syntax for VB.Net - but the specific topic you were looking at is treated the same in all these different versions of "Visual Basic". But it does appear from that web page that the Then in an If statement is an optional keyword in VB.Net, while it is required in VBA, so there's one difference on even such an elementary piece of coding.)
If you change your code from
If CDate(rst(3)) >= Date Then
ElseIf Cells(intFile, "CU") = "0" Then
Sheet1.Rows(r).EntireRow.Delete
to be
If CDate(rst(3)) >= Date And rst(98) <> 0 Then
I believe you will be doing what you set out to do, i.e. exclude all records where the 4th field (3 due to zero-base) is before today and also exclude all records where the 99th field is 0.

Related

Access - Is there a way to apply a filter via macro or VBA that does not overwrite existing filters?

I have a form built that has a SQL builder "search box" in the header. This allows the user to select a location and/or a date range to filter the records by if they wish.
I want to provide the user with options to further filter the records by the time that the record was recorded (in this situation by a standard work shift). For example I want to retrieve all records that have a time between 7 am and 7 pm. I can do this manually on the form, but I would rather have a button that runs a macro or VBA code that performs this without having to manually enter the values.
I have a macro set up that is:
RunMenuCommand
Command ApplyFilterSort
ApplyFilter
Where Condition = ((TimeValue([qryDiversion_Review].[Transaction_Time]) Between #7:00:00 AM# And #6:59:59 PM#))
This works, but it clears out any other filters that may be in place, for example if the user used any of the options on the header to filter by facility or date range.
Is there a way I can add this filter without removing any existing ones? I'm sure this is a simple solution, but I can't seem to figure it out yet.
Yes, you can just append a filter to the existing one in VBA. You need to check if the filter is set, though.
Me.Filter = IIF(Nz(Me.Filter, "") = "", "", Me.Filter & " AND ") & "TimeValue([qryDiversion_Review].[Transaction_Time]) Between #7:00:00 AM# And #6:59:59 PM#"
Me.FilterOn = True
Note that this doesn't take existing filters into account, so you might get conflicting filters (e.g. if a filter selecting all times between 6 and 7 AM was already set)

MS Access Tab Control Name with Number of Records

I am developing an Access database (using Office 2016) and have several tab controls which I want to display the number of records in the subform/subreport.
After a lot of searching etc I have it working for the subforms using a function which I call in the main forms current event (but in a seperate function so I can also call via a macro when I change the main forms record with a combo box, as it wasn't updating otherwise). The code I am using is:
Function ClientTotals()
Dim i As Integer
i = Form_sbfrm_ClientContacts.Recordset.RecordCount
Form_frm_Clients.ClientTabs.Pages("Contacts").Caption = "Contacts (" & i & ")"
End Function
This works perfectly for me and my tab name becomes "Contacts (No. of records)" but I can't get the syntax right to change this to work for a report, is it possible?
I have tried:
Function ClientTotals()
Dim i As Integer
i = Form_sbfrm_ClientContacts.Recordset.RecordCount
Form_frm_Clients.ClientTabs.Pages("Contacts").Caption = "Contacts (" & i & ")"
Dim j As Integer
j = Report_rpt_CurrentProjects.Recordset.RecordCount ' this line is highlighted with the debugger
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
End Function
As well as:
Dim j As Integer
j = rpt_CurrentProjects.Report.Recordset.RecordCount ' this line is highlighted with the debugger
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
and various others.
Another question I have is why is the syntax for the form "Form_sbfrm" etc and not using a "!". If I change to "!" it bugs out.
Thanks for your help, KAL
Thanks Delecron,
I think I will stick with the tabs for now as they are giving me exactly what I want, but remember what you have said for when I make future improvements if its a better way of doing it.
EDIT
Using what you have said I changed my VBA to a DCOUNT method:
Dim j As Integer
j = DCount("*", "qry_CurrentProjects", "FK_Project_Client_ID = Forms!Navigation!Navigationsubform.form!Client_ID")
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
This means my report tabs are now also working just how I wanted
I was getting in a muddle with the criteria/filter, hense the edit.
If Recordset is an old method I am assuming it would be best to replace my other code with the Dcount method?
Thanks again, KAL
Further EDIT
After doing this I could see that everytime the form was changed there was a slight flicker. Not bad but you could see there was a lot of calculation going on. Therefore I have changed my method to the following, and posted here for anyone looking at this in the future.
In the form footer a textbox with COUNT([Project_ID])
In my function
Dim j As Integer
j = Form_frm_Clients!rpt_CurrentProjects.Report!txt_CurrentProjectsCount.Value
Form_frm_Clients.ClientTabs.Pages("Current Projects").Caption = "Current Projects (" & j & ")"
Now I can see it is working quicker with no flicker.
Recordset if you need to return complex data, if you need one value, a total or a sum, Domain functions are the way to go. Don't overdue them though, having too many on a form or a report can start to bog down usability.
Glad I can help.
Recordset.Recordcount is a legacy feature that only worked in ADP files (Access front end's to a SQL database). Those are no longer supported.
If the report is based on 1 client only and there is no grouping then you can do this:
Click on the detail section and in Events create an event for On Paint. In there set
(Name of Page).Caption = DCount("*", "NAME OF QUERY/TABLE") or
(Name of Page).Caption = DCount("*", "NAME OF QUERY/TABLE", "Filter Expression") (Filter expression optional).
If the report is grouped where it will show a different page per client or date range or any other grouping this will not work since the Caption field is not data bound. You would have to add logic to the Dcount statement above to field by the current filter condition.
For example, say you have a database of 200 clients and you're running one big report on all of them, each page will get its own tab control per client, the syntax would be
(Name of Page).Caption = DCount("*", "ClientContacts, "ClientID = " & ClientID)
The better way to do it especially if you are grouping is get rid of the tab control and use databound controls. You could create a box around the information that would be in the tab page and put a textbox where the tab would go. Create a group header for however you are grouping the data. Create another invisible textbox in the group header and set the controlsource = Count([fieldname]) where fieldname is whatever you are grouping the data by (the inside brackets count).
Then in the textbox you created to simulate the tab, set the controlsource to the name of the invisible textbox.
Let me know if this helps.

Listbox.Listcount not accurate

Searched this and other sites but could not find an answer as to why I am not seeing a correct listcount for a listbox when adding items from a recordset.
Most other threads focus either on the count being off by one due to column headers on the listbox or a 65,534 physical limit.
I am seeing something a bit different
Running Access 2010 with linked SQL Server 2008 tables.
Code:
lstSearchResults.RowSource = ""
lstSearchResults.AddItem ("Material Number;Description")
Set rsParts = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot)
If rsParts.RecordCount > 0 Then
rsParts.MoveLast
rsParts.MoveFirst
lngCount = 0
Do While Not rsParts.EOF
lngCount = lngCount + 1
lstSearchResults.AddItem (rsParts.Fields("MaterialNumber") & ";" & rsParts.Fields("Description"))
rsParts.MoveNext
Loop
End If
Placing a breakpoint just after the loop I examined the following values:
lstSearchResults.ListCount - 1012
rsParts.RecordCount - 5255
lngCount - 5255
Since you're using the AddItem method, that means your list box's Row Source Type property must be "Value List". And that means the Record Source property is a string which contains that list of values. And there is a limit to the number of characters which can be included in a value list. Although I don't recall the number for that limit, I suspect that is the reason your value list does not contain all the values you expect.
But there is a simpler way to load the list box values. You have a query, strSQL, for which you open a recordset, then walk the recordset to add 2 field values from each row to the value list.
Use the SQL statement directly ... without the recordset as an intermediary.
Change the list box's Row Source Type to "Table/Query".
Use the SQL statement as the list box's Row Source property.
That approach is less fuss and avoids the Value List character limit. Then you only need to decide whether 1K or more rows is really appropriate for a list box. :-)

Access Report won't allow me to refer to a field in VBA unless it's on the report in its own right

So, in an Access Form or Report a good way to show something dynamic on the screen that is more complex than =[UnitPrice]*[Quantity] is to drop into VBA.
e.g. in this simplified example, the underlying table for this Report has two fields ShowTax and TaxRate. By making a TextBox's control source =GetTaxInfo I get to introduce some complexity in VBA:
Public Function GetTaxInfo() As String
Dim result As String
If Me!ShowTax = 0 Then
result = "Tax included # " & Me!TaxRate
Else
result = ""
End If
GetTaxInfo = result
End Function
OK, this works ... so long as I have a field somewhere else that refers to TaxRate. Otherwise it just prints #Error. It's as if it needs to preload the field before it can be used in VBA code. It isn't the end of the world because I can have a bunch of fields in the report all set to not be visible, but it's untidy.
So is it the case that you can't refer to a field in VBA code backing a report unless you have already referred to the field in the conventional way as a field baked into the report?
I can't remember encountering this limitation before. Or is it that I have a corrupt report? (I have tried the usual compact/repair, export/reimport the Report etc)
Edit:
the weird thing is ... now it's working again. And - I'm pretty sure - there is no control in the report. which is why I was thinking it was a corruption in the report.
You'll need a control on the form/report.
If this is too messy, you could put the function in a Module and use in the RecordSource (based on a query). No sense burying all this logic in a report when it could be used in other places as well.
Public Function GetTaxInfo(ShowTax as Boolean, TaxRate as Single) As String
Dim result As String
If ShowTax = 0 Then
result = "Tax included # " & TaxRate
Else
result = ""
End If
GetTaxInfo = result
End Function
Then the control is set to this field in this report and others.

Access VBA Formatting

Hey all, I managed to integrate my Database quite well with Excel in the end, but in the end after I showed it to the bosses they asked me to develop the forms and reports in Access again. That did not take too long fortunately, so I ended up doing two front ends for one back end Database. But in the end it'll be a fully Access database with only one bit of Excel integration utilized; basically the transfer spreadsheet method to transfer daily end of trade Share price into Access.
Now I've come to a point where the database is pretty much ready to be split and populated.(What's the best way to tackle this, populate first or split first?)
The question I'm asking is below:
This might seem like a fairly simple question but so far, I haven't been helped with google or maybe I'm not using the right keywords in my search so I thought what better place to ask then on here; Is there a way to format the numbers that are generated through some VBA code and placed in a new table in Access, to make them look like:
So if it's 1,000,000 then it would appear as 1m
Or if it's 10,000 then it appears as 10k
So basically if it has three 0's then it's a K
If it has six 0's then it's an M
I have used some VBA initially to format the numbers in the following way:
ChangeInShare = Format(ChangeInShare, "#,##.00")
But then the request came to shorten some numbers down to make the reports look neater.
The final table, takes the values in a Text format btw.
Thank you
You can use the modulo operator to test if the number is dividable by 1000000 or by 1000 and then replace the last zeros.
Maybe this function points you to the right direction:
Public Function fmt(val As Long) As String
Dim result As String
If val Mod 1000000 = 0 Then
result = (val \ 1000000) & "M"
ElseIf val Mod 1000 = 0 Then
result = (val \ 1000) & "K"
Else
result = val
End If
fmt = result
End Function
Then some test calls:
? fmt(471000)
471K
? fmt(4711)
4711
? fmt(4000000)
4M
? fmt(40000)
40K
Hi Muffi D
additional to vanjes acceptable very good answer there is another idea:
what about the scientific notation?
Debug.Print FStr(10)
Debug.Print FStr(2000)
Debug.Print FStr(300000)
Debug.Print FStr(40000000)
Debug.Print FStr(5000000000#)
Debug.Print FStr(12)
Debug.Print FStr(2345)
Debug.Print FStr(345678)
Debug.Print FStr(45678901)
Debug.Print FStr(5678901234#)
Function FStr(ByVal d As Double) As String
FStr = Format(d, "0.####E+0")
End Function
then you will get:
1,0E+1
2,000E+3
3,E+5
4,E+7
5,E+9
1,2E+1
2,345E+3
3,4568E+5
4,5679E+7
5,6789E+9
if you need for Doubles (or Currency) you can go with vanjes answer but use the ModF-function instead:
Function ModF(ByVal value As Double, _
ByVal div As Double) As Double
ModF = value - (Int(value / div) * div)
End Function
Function fmtF(ByVal value As Double) As String
Dim result As String
If ModF(value, 1000000000) = 0 Then
result = (value / 1000000000) & "G"
ElseIf ModF(value, 1000000) = 0 Then
result = (value / 1000000) & "M"
ElseIf ModF(value, 1000) = 0 Then
result = (value / 1000) & "K"
Else
result = value
End If
fmtF = result
End Function
regards
Oops
You can split your database anytime before distribution to your users but I don't know what you mean by "populate."
See the "Splitting your app into a front end and back end Tips" page for info on splitting.. See the free Auto FE Updater utility to make the distribution of new FEs relatively painless.
I was also wondering; I have a CurrencyCode which defines whatever type of currency the Company is in; now all the calculations in VBA are done already. I wanted to know is there a way to write a SQL statement where for example; if the CurrencyCode=GBP then the resultant field is displayed as £23m instead of 23m etc for all the different currencies that are there in the field.
This again, needs to be hard-coded right now; the only thing is, if in the future if I'm not with the company, someone has to add a company in, which doesn't have the code to do that; then what will be the way to deal with? Will they have to have someone that needs to know about how to use SQL or VBA and be able to change; for this I would prefer doing it in SQL if possible because then I could put this in a manual for the database and SQL is much less daunting to use then VBA for beginners.
The resultant values have to be in the same column, so all the different IF's and Wheres need to be part of the same SQL statement, this is because of the reports that are there which use a single column for the different companies with different currencies.
Thanks!