Set field format in query to report - ms-access

Is there a way for a report's field to take into account the format of a field in a query?
In example:
I have a StudentPercent field in a query. Values of the field are between 0 to 1, but since it is formatted to percent, they appear from 0% to 100% . When I run the report, it doesn't consider the format of the field and the values are between 0 to 1. Why is that?
Edit 1: I'm using Microsoft Access 2016.
Also, datas are populated dynamically, so I can't just set the format of the fields manually.
Edit 2:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
'Exit Sub
' Place values in text boxes and hide unused text boxes.
Dim intX As Integer
' Verify that not at end of recordset.
If Not rstReport.EOF Then
' If FormatCount is 1, place values from recordset into text boxes
' in detail section.
If Me.FormatCount = 1 Then
Me("Col" + Format(intColumnCount + 1)) = 0
For intX = 1 To intColumnCount
' Convert Null values to 0.
Me("Col" + Format(intX)) = Nz(rstReport(intX - 1))
If intX < intColumnCount Then
Me("Col" + Format(intColumnCount + 1)) = _
Me("Col" + Format(intColumnCount + 1)) + Nz(rstReport(intX))
End If
Next intX
' Hide unused text boxes in detail section.
'For intX = intColumnCount + 2 To conTotalColumns
'Me("Col" + Format(intX)).Visible = False
'Next intX
For intX = 2 To intColumnCount + 1
Me("Tot" + Format(intX)) = Nz(Me("Tot" + Format(intX))) + Nz(Me("Col" + Format(intX)))
Next intX
' Move to next record in recordset.
rstReport.MoveNext
End If
End If
End Sub
^ is the code of the detail part of my report.
I'm getting the error '13' - Type mismatch when I run the report after casting my field with Format(FieldName, "Percent") and the following code is highlighted:
Me("Col" + Format(intColumnCount + 1)) = _
Me("Col" + Format(intColumnCount + 1)) + Nz(rstReport(intX))

Set the Format property of the textbox in the report to: Percent
Or, expand the source query to have a field returning the formatted value as text:
StudentPercentText: Format([StudentPercent],"Percent")
Then use this field in your report and not the StudentPercent field. However, this is text, so you cannot use such a field in a calculation in the report.

Related

MS Access Update Query based on Index Number and other Criteria

I have a function I am trying to do for a database I am working on for my job. I'm not the most proficient with Access so I apologize if I am not wording this in the best way.
What I am trying to do is create a query/macro that will mimic the behavior as shown
and result into this:
The logic is as follows
1) for each record - take the LEN of the string in StdName. Take that number of characters and UPDATE that to the Name field. The remaining characters after the LEN is moved to the 'SuffixString' Field
2)for each record - count the number of occurrences of the string in the 'StdName' field for any records ON OR BEFORE the index number and UPDATE the 'Name' field with whatever is in there already and concatenate with "_n" where n is the occurence
example: index 1 - has one occurrence of 'Car1' in the StdName Field between record 1 and record 1. index 1 'Name' is changed to Car1_1
example: index 2 - has two occurrences of 'Car1' in the StdName Field between record 1 and record 2. index 2 'Name' is changed to Car1_2
example: index 6 - has one occurrence of 'Car3" in the StdName Field between record 1 and record 6. index 6 'Name' is changed to Car3_1
Can something like this be done with an access query? I've never developed in Access before and my boss really wants to see this function kept inside access instead of being moved in an out of excel.
(I have step 1 setup this way to later put in logic where StdName does not match Name. example: "Car1_1" for Name and StdName "Car2". I realize I could just Concatenate StdName with the function in step 2 in this example i described, but I have a real world purpose of doing it this way)
This will be done on an MDB format
Thank you
You can use my RowCounter function:
SELECT RowCounter(CStr([Index]),False,[StdName])) AS RowID, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
or:
SELECT [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))) AS RankedName, *
FROM YourTable
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Edit - to update:
UPDATE s_before
SET [Name] = [StdName] & "_" & CStr(RowCounter(CStr([Index]),False,[StdName]))
WHERE (RowCounter(CStr([Index]),False) <> RowCounter("",True));
Code:
Public Function RowCounter( _
ByVal strKey As String, _
ByVal booReset As Boolean, _
Optional ByVal strGroupKey As String) _
As Long
' Builds consecutive RowIDs in select, append or create query
' with the possibility of automatic reset.
' Optionally a grouping key can be passed to reset the row count
' for every group key.
'
' Usage (typical select query):
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' Usage (with group key):
' SELECT RowCounter(CStr([ID]),False,CStr[GroupID])) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter(CStr([ID]),False) <> RowCounter("",True));
'
' The Where statement resets the counter when the query is run
' and is needed for browsing a select query.
'
' Usage (typical append query, manual reset):
' 1. Reset counter manually:
' Call RowCounter(vbNullString, False)
' 2. Run query:
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable;
'
' Usage (typical append query, automatic reset):
' INSERT INTO tblTemp ( RowID )
' SELECT RowCounter(CStr([ID]),False) AS RowID, *
' FROM tblSomeTable
' WHERE (RowCounter("",True)=0);
'
' 2002-04-13. Cactus Data ApS. CPH
' 2002-09-09. Str() sometimes fails. Replaced with CStr().
' 2005-10-21. Str(col.Count + 1) reduced to col.Count + 1.
' 2008-02-27. Optional group parameter added.
' 2010-08-04. Corrected that group key missed first row in group.
Static col As New Collection
Static strGroup As String
On Error GoTo Err_RowCounter
If booReset = True Then
Set col = Nothing
ElseIf strGroup <> strGroupKey Then
Set col = Nothing
strGroup = strGroupKey
col.Add 1, strKey
Else
col.Add col.Count + 1, strKey
End If
RowCounter = col(strKey)
Exit_RowCounter:
Exit Function
Err_RowCounter:
Select Case Err
Case 457
' Key is present.
Resume Next
Case Else
' Some other error.
Resume Exit_RowCounter
End Select
End Function

Random number using Date() in Expression Builder

I want to generate random number using Date() to format it like for example: ddmmyyyyHhNnSs
How do I achieve that? Is that even possible?
I was kinda hoping I can do it easy way by the expression builder but I seem to fail on each approach ;)
This number need to populate txtID field and it will be unique identifier for each database entry.
That's quite easy - with a twist.
Problem is that Rnd only returns a Single and the resolution of this only allows for 10000000 unique values. As you request a resolution to the second and with 86400 seconds per day, that only leaves a span of 115.74 days while the range of Date spans 3615899 days:
TotalDays = -CLng(#1/1/100#) + CLng(#12/31/9999#)
To overcome this, use Rnd twice which will result in 1E+15 possible values or 11574074074 days - way beyond what's needed:
RandomDouble = Rnd * Rnd
Now, to limit the possible values to fit into the range of data type Date, just follow the documentation:
RandomValue = (UpperValue - LowerValue) * Rnd + LowerValue
and apply the date values:
RandomDouble = (CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#)
This, however, will result in values containing unwanted milliseconds, thus perform the proper conversion to Date value using CDate which will round to the nearest second, and you have the final expression:
RandomDate = CDate((CLng(#12/31/9999#) - CLng(#1/1/100#)) * Rnd * Rnd + CLng(#1/1/100#))
Use the value as is if your field is of datatype Date or - if text - apply a format to this with Format(RandomDate, "yyyymmddhhnnss") and a sample output will be:
01770317032120
01390126010945
50140322081227
35290813165627
09330527072433
20560513105943
61810505124235
09381019130230
17010527033132
08310306233911
If you want numeric values, use CDec to convert (CLng will fail because of overflow):
RandomNumber = CDec(Format(RandomDate, "yyyymmddhhnnss"))
All said, I'm with #Bohemian - if you just want a unique timestamp and have less than one transaction per second, just use data type Date for your field and use Now:
TimeStamp = Now()
and apply a format to this of yyyymmddhhnnss.
However, Multiplying random numbers together alters the
probablility distribution:
Uniform Product Distribution
Thus, a better method is to create a random date, then a random time, and possibly a random count of milliseconds - I wrote above, that CDate rounds a value to the nearest second; it doesn't, only whenever Access displays a date/time with milliseconds the displayed valued is rounded to the second.
So I modified the function to take care of this:
Public Function DateRandom( _
Optional ByVal UpperDate As Date = #12/31/9999#, _
Optional ByVal LowerDate As Date = #1/1/100#, _
Optional ByVal DatePart As Boolean = True, _
Optional ByVal TimePart As Boolean = True, _
Optional ByVal MilliSecondPart As Boolean = False) _
As Date
' Generates a random date/time - optionally within the range of LowerDate and/or UpperDate.
' Optionally, return value can be set to include date and/or time and/or milliseconds.
'
' 2015-08-28. Gustav Brock, Cactus Data ApS, CPH.
' 2015-08-29. Modified for uniform distribution as suggested by Stuart McLachlan by
' combining a random date and a random time.
' 2015-08-30. Modified to return selectable and rounded value parts for
' Date, Time, and Milliseconds.
' 2015-08-31. An initial call of Randomize it included to prevent identical sequences.
Const SecondsPerDay As Long = 60& * 60& * 24&
Dim DateValue As Date
Dim TimeValue As Date
Dim MSecValue As Date
' Shuffle the start position of the sequence of Rnd.
Randomize
' If all parts are deselected, select date and time.
If Not DatePart And Not TimePart And Not MilliSecondPart = True Then
DatePart = True
TimePart = True
End If
If DatePart = True Then
' Remove time parts from UpperDate and LowerDate as well from the result value.
' Add 1 to include LowerDate as a possible return value.
DateValue = CDate(Int((Int(UpperDate) - Int(LowerDate) + 1) * Rnd) + Int(LowerDate))
End If
If TimePart = True Then
' Calculate a time value rounded to the second.
TimeValue = CDate(Int(SecondsPerDay * Rnd) / SecondsPerDay)
End If
If MilliSecondPart = True Then
' Calculate a millisecond value rounded to the millisecond.
MSecValue = CDate(Int(1000 * Rnd) / 1000 / SecondsPerDay)
End If
DateRandom = DateValue + TimeValue + MSecValue
End Function
Format now() and cast to a long:
select CLng(format(now(), 'ddmmyyyyhhnnss')) as txnId
Although this is not "random", it is unique as long as there are never more than one transaction per second (confirmed in comment above).

Formatting Datetime in SSRS Expression

Part of my query is like so:
SELECT * FROM TableA
WHERE ColumnA >= DATEADD(DAY, - 30, GETDATE())
With the expression at the where clause above, you can pull a rolling 30 days data without having to supply values. Now users of the report want to see it represented like:
2nd April – 1st May
when the report is ran. Knowing that I have no parameters as the requirement is to not use parameters, how do I reference ">= DATEADD(DAY, - 30, GETDATE())" to reflect the start date and the end date in the report?
SSRS doesn't have built-in support for ordinal numbers (i.e. "1st" or "2nd" instead of "1" or "2"). This page contains custom code to add this functionality to your SSRS report; however it is slightly wrong. Here is a corrected version:
Public Function FormatOrdinal(ByVal day As Integer) as String
' Starts a select case based on the odd/even of num
if(day = 11 or day = 12 or day = 13)
' If the nymber is 11,12 or 13 .. we want to add a "th" NOT a "st", "nd" or "rd"
return day.ToString() + "th"
else
' Start a new select case for the rest of the numbers
Select Case day Mod 10
Case 1
' The number is either 1 or 21 .. add a "st"
Return day.ToString() + "st"
Case 2
' The number is either a 2 or 22 .. add a "nd"
Return day.ToString() + "nd"
Case 3
' The number is either a 3 or 33 .. add a "rd"
Return day.ToString() + "rd"
Case Else
' Otherwise for everything else add a "Th"
Return day.ToString() + "th"
End Select
end if
End Function
If you add this code to the code section of your report under report properties, your textbox expression would be:
Code.FormatOrdinal(Day(Globals!ExecutionTime)) & " " & MonthName(Month(Globals!ExecutionTime), False) & " - " & Code.FormatOrdinal(Day(DateAdd("d", -30,Globals!ExecutionTime))) & " " & MonthName(Month(DateAdd("d", -30,Globals!ExecutionTime)), False)

Right Click on the Textbox, Go To Textbox Properties then, Click on Number tab, click on custom format option then click on fx button in black.
Write just one line of code will do your work in simpler way:
A form will open, copy the below text and paste there to need to change following text with your database date field.
Fields!FieldName.Value, "Dataset"
Replace FieldName with your Date Field
Replace Dataset with your Dateset Name
="d" + switch(int(Day((Fields!FieldName.Value, "Dataset"))) mod 10=1,"'st'",int(Day((Fields!FieldName.Value, "Dataset"))) mod 10 = 2,"'nd'",int(Day((Fields!FieldName.Value, "Dataset"))) mod 10 = 3,"'rd'",true,"'th'") + " MMMM, yyyy"

Use alphabet as counter instead of number in vba

I want to append an alphabet incrementally like for variable say
I pass JohnBox then it should be JohnBox_a then the next time it would be:
JohnBox_b
.
.
JohnBox_z
JohnBox_aa
.
.
JohnBox_zz
Can someone please help regarding solving this issue? This is what I have tried so far but Case 2 is where I am having problems:
Public Function fCalcNextID(strID As String) As Variant
Dim strName As String
'Extract Numeric Component
strName = Left(strID, InStr(strID, "_"))
If Len(Nz(strName, "")) = 0 Then
strName = strID
Else
strName = strName
End If
Select Case Len(Right(strID, (Len(strID) - (InStr(strID, "_")))))
Case 1 'single alpha (a)
If Right$(strID, 1) = "z" Then
fCalcNextID = strName & "aa"
Else
fCalcNextID = strName & Chr$(Asc(Right$(strID, 1)) + 1)
End If
Case 2 'double alpha (bd)
If Right$(strID, 1) = "z" Then
If Mid$(strID, 4, 1) = "z" Then
fCalcNextID = CStr(strName + 1) & "a"
Else
fCalcNextID = CStr(strName) & Chr$(Asc(Mid$(strID, 4)) + 1) & "a"
End If
Else '101bd, 102tx, etc.
'Increment last character, 101bd ==> 101be
fCalcNextID = Left$(strName, 4) & Chr$(Asc(Right$(strID, 1)) + 1)
End If
Case Else
fCalcNextID = strName & "_a"
End Select
End Function
The solution to your problem can be found in this LINK already. Credits to UtterAccess Wiki
The link presents 2 functions: Base10ToBaseLetter and BaseLetterToBase10. The functions are shown below just in case the link changes or become unavailable.
Public Function Base10ToBaseLetter(ByVal lngNumber As Long) As String
' Code courtesy of UtterAccess Wiki
' http://www.utteraccess.com/wiki/index.php/Category:FunctionLibrary
' Licensed under Creative Commons License
' http://creativecommons.org/licenses/by-sa/3.0/
'
' You are free to use this code in any application,
' provided this notice is left unchanged.
' ================================================================================
' Concept:
' Base10: Decimal 123 => (1 * 10 ^ 2) + (2 * 10 ^ 1) + (3 * 10 ^ 0)
' Base26: Decimal 123 => ( 4 * 26 ^ 1) + (19 * 26 ^ 0)
' Representing 4 and 19 with letters: "DS"
' MSD = Most Significant Digit
' LSD = Least Significant Digit
' ================================================================================
' Returns ZLS for input values less than 1
' Error handling not critical. Input limited to Long so should not normally fail.
' ================================================================================
Dim intBase26() As Integer 'Array of Base26 digits LSD (Index = 0) to MSD
Dim intMSD As Integer 'Most Significant Digit Index
Dim n As Integer 'Counter
If lngNumber > 0 Then
' Calculate MSD position (Integer part of Log to Base26 of lngNumber)
' Log of X to Base Y = Log(X) / Log(Y) for any Base used in calculation.
' (VBA Log function uses the Natural Number as the Base)
intMSD = Int(Log(lngNumber) / Log(26))
ReDim intBase26(0 To intMSD)
For n = intMSD To 0 Step -1
' Calculate value of nth digit in Base26
intBase26(n) = Int(lngNumber / 26 ^ n)
' Reduce lngNumber by value of nth digit
lngNumber = lngNumber - ((26 ^ n) * intBase26(n))
Next
' Base Letter doesn't have a zero equivalent.
' Rescale 0 to 26 (digital representation of "Z")
' and "borrow" by decrementing next higher MSD.
' Digit can be -1 from previous borrow onto an already zero digit
' Rescale to 25 (digital representation of "Y")
' Looping from LSD toward MSD
' MSD not processed because it cannot be zero and
' avoids potential out of range intBase26(n + 1)
For n = 0 To intMSD - 1
If intBase26(n) < 1 Then
intBase26(n) = 26 + intBase26(n) ' Rescale value
intBase26(n + 1) = intBase26(n + 1) - 1 ' Decrement next higher MSD
End If
Next
' Ignore MSD if reduced to zero by "borrow"
If intBase26(intMSD) = 0 Then intMSD = intMSD - 1
' Convert Base26 array to string
For n = intMSD To 0 Step -1
Base10ToBaseLetter = Base10ToBaseLetter & Chr((intBase26(n) + 64))
Next
End If
End Function
Public Function BaseLetterToBase10(ByVal strInput As String) As Long
' Upper or lower case characters accepted as input
' ZLS returns 0
' Negative return value indicates error:
' Unaceptable character or Overflow (string value exceeds "FXSHRXW")
' Digit indicates character position where error encountered
' MSD = Most Significant Digit
Dim intMSD As Integer 'MSD Position
Dim intChar As Integer 'Character Position in String
Dim intValue As Integer 'Value from single character
Dim n As Integer 'Counter
On Error GoTo ErrorHandler
' Convert String to UpperCase
strInput = UCase(strInput)
' Calculate Base26 magnitude of MSD
intMSD = Len(strInput) - 1
For n = intMSD To 0 Step -1
intChar = intMSD - n + 1
intValue = Asc(Mid(strInput, intChar, 1)) - 64
' Test for character A to Z
If intValue < 0 Or intValue > 26 Then
BaseLetterToBase10 = -intChar
Exit For
Else
' Add Base26 value to output
BaseLetterToBase10 = BaseLetterToBase10 + intValue * 26 ^ n
End If
Next
Exit Function
ErrorHandler:
BaseLetterToBase10 = -intChar: Exit Function
End Function
Now to apply it to your needs, you simple call those functions:
Public Function fCalcNextID(strID As String) As String
Dim CurIdx As String, n As Integer, x As Long
On Error Resume Next
CurIdx = UCase(Split(strID, "_")(1))
On Error GoTo 0
If CurIdx <> "" Then
x = BaseLetterToBase10(CurIdx) + 1
fCalcNextID = Split(strID, "_")(0) & "_" & LCase(Base10ToBaseLetter(x))
Else
fCalcNextID = strID & "_a"
End If
End Function
This is not me. It is them. What I did is just ask Google to find it for me.
Nonetheless hope this helps and is actually what you need.
Important: Don't remove the comments. That is the only request of the author.
What you have is essentially a base26 count. You can implement that with a modulus function instead of your current code. You will have to create the VBA code yourself, just getting you the algoritm:
For example:
Create an array with a-z
Input a value:
cde
Convert to numeric: 3*26*26+4*26+5
Add 1: 3*26*26+4*26+5+1
input=3*26*26+4*26+6
LOOP until input equals 0:
Mod(input,26) returns remnant (first loop:6, 2nd loop: 4, 3rd loop: 3) => look up in array => f (first loop) (2nd loop d, third loop c).
returnval=lookup value+returnval;
input=Divide (input - mod output (input))/26
END LOOP

SSRS page numbers in page footer

I wish to not include the page number (in the page footer) for the first 10 pages of the report (i.e. page 1-10). Page 1 should read i, page 2 should read ii and page 3 should read iii and so on (in roman numerals).... When it gets to page 11, this should reset the page numbers
Does anyone know of the expression I can use to achieve this. So if GlobalPage number = 1,2,3,4,5,6,7,8,9,10 do not display, or compensate the globals page number for something else.....Is this possible.
You'll have to manually change the value i.e. putting something similar to the following in the footer:
IIf(Globals!PageNumber=1, "i", ...
Alternativally you could use a user function try VBA for number to roman numeral
We'll do ths with some custom code to keep flexibility. Microsoft have some code to do the Roman numeral conversion so we'll adapt this.
Let's add the custom code we need: one function to convert an integer to a Roman numeral and one function to work out what sort of numeral to provide.
Function PageNumber(page As Integer, startArabic As Integer) As String
If page <= startArabic Then
PageNumber = IntegerToRoman(page)
Else
PageNumber = (page - startArabic).ToString()
End If
End Function
Function IntegerToRoman (ByVal N As Integer) As String
Const Digits = "ivxlcdm"
Dim I As Integer
Dim Digit As Integer
Dim Temp As String
I = 1
Temp = ""
Do While N > 0
Digit = N Mod 10
N = N \ 10
Select Case Digit
Case 1
Temp = Mid(Digits, I, 1) & Temp
Case 2
Temp = Mid(Digits, I, 1) & Mid(Digits, I, 1) & Temp
Case 3
Temp = Mid(Digits, I, 1) & Mid(Digits, I, 1) & Mid(Digits, I, 1) & Temp
Case 4
Temp = Mid(Digits, I, 2) & Temp
Case 5
Temp = Mid(Digits, I + 1, 1) & Temp
Case 6
Temp = Mid(Digits, I + 1, 1) & Mid(Digits, I, 1) & Temp
Case 7
Temp = Mid(Digits, I + 1, 1) & Mid(Digits, I, 1) & Mid(Digits, I, 1) & Temp
Case 8
Temp = Mid(Digits, I + 1, 1) & Mid(Digits, I, 1) & Mid(Digits, I, 1) & Mid(Digits, I, 1) & Temp
Case 9
Temp = Mid(Digits, I, 1) & Mid(Digits, I + 2, 1) & Temp
End Select
I = I + 2
Loop
IntegerToRoman = Temp
End Function
To make the report more flexible, we'll add a parameter for when to revert to Arabic numerals (in case we need more than ten Roman numerals at some stage when the report gets longer). Let's call that #StartArabic and it will be an integer with the default value of 10. So now our page number expression is simply:
="Page " & Code.PageNumber(Globals!PageNumber, Parameters!StartArabic.Value)