access fields same but not equal? - ms-access

i'm using the following code to compare two recordsets:
For i = 1 To (recordsetA.Fields.Count - 1)
If recordsetA.Fields(i).Value <> recordsetB.Fields(i).Value Then
stringFieldList = stringFieldList & ", " & recordsetA.Fields(i).Name
End If
Next i
However in the stringFieldList there are a couple of fields which have the same values (like 1339.5). Why?

Since it sounds like your dealing with double datatypes, the proper way for the test would be to set a limit, then test the absolute difference. You will also need to think about handling a null value.
Const epsilon as double = 0.00001
If Abs(recordsetA.Fields(i).Value - recordsetB.Fields(i).Value) < epsilon Then
'do stuff here
End If

Related

IIf query decimal removal

Trying to attempt the following in MS Access.
Convert data in one field to an 18 digit number starting with 01 in another field.
There are also some conditions that have to be met:
the first dash should become double zeros
the second dash should be removed
the third and fourth dash should be a single zero
the decimal must also be replaced with a zero
My query works fine until the decimal is the 15th character in the data.
Here is the query:
SELECT MasterVacant.ParcelIdNumber,
"01" + Mid([ParcelIdNumber],1,2) + "00" + Mid([ParcelIdNumber],4,2) + Mid([ParcelIdNumber],7,1)
+ IIf(Mid([ParcelIDNumber],11,1) = "", "0"+Mid([ParcelIDNumber],9,2), Mid([ParcelIDNumber],9,3))
+ IIf(Mid([ParcelIDNumber],14,1) = ".", "0"+Mid([ParcelIDNumber],12,2), Mid([ParcelIDNumber],12,3))
+ Mid([ParcelIDNumber],15,3) AS ParcelNumber
FROM MasterVacant;
Here is a start and finish example...
'12-06-1-00-50.000-RR' should become '011200061000050000'
'12-06-3-07-09.000-RR' should become '011200063007009000'
'13-35-1-01-129.000-RR' should become '011300035100112900'
However, instead of getting `0113000351001129000' I get '013000351001129.00'.
The issue is how do I remove the decimal when the decimal is the 15th character like in the third set of example?
I receive the data as a single column. Some of it is below....
1. 13-35-1-07-29.000-RR
2. 13-35-1-01-112.000-RR (Removing the decimal when the data is like this is the issue)
3. 13-35-4-01-01.000-RR
4. 13-35-4-02-04.000-RR
5. 13-35-1-13-17.000-RR
The output for the above data should be
1. 011300351007029000
2. 011300351001112000
3. 011300354001001000
4. 011300354002004000
5. 011300351013017000
Use a custom function:
Public Function Make18(ByVal Value As String) As String
Const Head As String = "01"
Const Tail As String = "000"
Const Lead As String = "00"
Dim Parts As Variant
Dim Part As Integer
Dim Result As String
Parts = Split(Split(Value, ".")(0), "-")
For Part = LBound(Parts) To UBound(Parts)
Select Case Part
Case 0
Parts(Part) = Head & Parts(Part)
Case 1
Parts(Part) = Lead & Parts(Part)
Case 3, 4
Parts(Part) = Right(Lead & Parts(Part), 3)
End Select
Next
Result = Join(Parts, "") & Tail
Make18 = Result
End Function
and your query becomes:
SELECT
MasterVacant.ParcelIdNumber,
Make18([ParcelIdNumber]) AS ParcelNumber
FROM
MasterVacant;
I am assuming you meant the opposite where:
12-06-1-00-50.000-RR should become 011200061000050000
12-06-3-07-09.000-RR should become 011200063007009000
13-35-1-01-129.000-RR should become 0113000351001129.00
I would recommend the REPLACE() in MSACCESS to strip the dashes out. Once you have the dashes out you can MID()
Unfortunately your attempted code does something different with the 3rd row because 3 zeros are being put in when there should be only two in my opinion.
Try in a text box:
=Replace("13-35-1-01-129.000-RR","-","")
will return 1335101129.000RR
and see if that assists you in making your code.
Maybe go one step further and put it in a function.

microsoft access Field must be blank or have a value that is a specific length

I have a field on a form and I need the user to leave it blank or enter a value that is a specific length (20 characters). Does anyone have code that may solve this need?
I have tried:
(Len([SIM / ENGRV]) = 20) or (isnull([SIM / ENGRV])) or ([SIM / ENGRV]="")
I assume the control (field) name in the form is Text1.
So you can use this code in the before update event .
Of course, the code can be much shorter,
But I think that's the clearest way to understand the logic.
Private Sub Text1_BeforeUpdate(Cancel As Integer)
Dim varTmp As Variant
' first check if [ENGRV] > 0 to avoid devision by zero error
If Not IsNumeric([ENGRV]) And [ENGRV] = 0 Then
Text1.Undo
Cancel = True
Else
' now avoid [SIM] is null error
If Nz([SIM], "") = "" Then
Text1.Undo
Cancel = True
Else
varTmp = [SIM] / [ENGRV]
' now we know that varTmp is somthing and not empty then check the length
If Len(Trim(str(varTmp))) <= 20 Then
Text1.Undo
Cancel = True
End If
End If
End If
End Sub
You can do that at the table level. Set the Validation Rule of the field to:
Len([SIM / ENGRV])=20 Or [SIM / ENGRV] Is Null

qlikview set expression with chr()-function

I am Setting some variables in the script of my qlikview application. Later on I try to reuse one of the previous variables but qlikview is giving me an error.
SET vCurrentMonth = "=CAL.MONTH";
SET vMonthCounter = "SUM({<MONTH = {'$(vCurrentMonth)'}>} Counter)";
I was trying to use the $-expansion as already known from the normal set expressions that are not in the Script. But then I did not receive any data.
After some Research I found that I must replace the $ with the chr()-function.
SET vMonthCounter = "SUM({<MONTH = {'" & chr(36)& "(vCurrentMonth)'}>} Counter)";
But this chr()-function is returning a string so I don't receive the sum of my Counter but the string of the set Expression ($03).
What am I doing wrong? Can anybody explain how to use this function in the script?
Thanks in advance
It works fine for me even without using the chr() function. I've added = before the sum (i've used simple string for vCurrentMonth and remove the = there):
SET vMonthCounter = "=SUM({<MONTH = {'$(vCurrentMonth)'}>} Counter)";
and then using the variable in text box (like below) is giving me the correct result:
= vMonthCounter
If you still prefer the chr() approach then some changes in the vMonthCounter are needed to get the same result:
let vMonthCounter1 = '=SUM({ <category = {' & chr(39) & chr(36) & '(vCurrentMonth)' & chr(39) & '} >} value)';
set is replaced with let. let evaluates the expression and will actually run and replace the chr() with the symbols (btw when using set you are not obligated to enclose the string in any quotes)
replaced the start and end quotes with single quote
the single quotes inside the set expressions are replaced with chr(39)

Using .Find in a Recursive Function

I am trying to find the row number in a sheet using the .Find function in a recursive function.
I set an object called Found = .Find.... and it works great... for a little bit. I set it when I'm 1 level of recursion deep, then set it again when I'm 2 levels deep. Then, my code finds the end of the path and starts backing up until it gets back to 1 level deep, but not my Found object has been re-declared and kept its values from the 2nd level. My other variables (ThisRow etc...) keep the value of the level that they are in, and that's what I would like to do with the object Found. Is there a way that I can declare Found locally so that it's value doesn't extend to the next function, and can't be overwritten in a deeper level? You can find my code below for reference.
Here is my current code - irrelevant parts cut out:
Public Function FindChildren()
ThisRow = AnswerRow 'Also declared before function call
BeenHereCell = Cells(ThisRow, "O").Address
If Range(BeenHereCell).Value = "Yes" Then
Exit Function 'That means we've already been there
End If
Range(BeenHereCell).Value = "Yes"
With Worksheets("MasterScore").Range("j1:j50000")
Set Found = .Find(NextQuestionID, LookIn:=xlValues)
If Not Found Is Nothing Then
firstAddress = Found.Address
NextCell = Found.Address
Do
AnswerRow = Range(NextCell).Row
FindChildren 'This is where it's recursive.
Set Found = .FindNext(Found)
NextCell = Found.Address
Loop While Not Found Is Nothing And Found.Address <> firstAddress
End If
End With
End Function
Now I have gotten around it by activating cells, but it makes my code a lot slower. Currently I am using this:
Set Found = Worksheets("MasterScore").Range("j1:j50000").Find(NextQuestionID, LookIn:=xlValues)
If Not Found Is Nothing Then
Count = 1
Do
Columns("J:J").Select
FirstFoundRow = Selection.Find(What:=NextQuestionID, After:=ActiveCell, LookIn:= _
xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:= _
xlNext, MatchCase:=False, SearchFormat:=False).Row
For i = 1 To Count
Selection.FindNext(After:=ActiveCell).Activate
Next i
AnswerRow = ActiveCell.Row
If AnswerRow = FirstFoundRow And Count <> 1 Then Exit Do
FindChildren
Count = Count + 1
Loop
End If
This way, I don't have to set the value of the object again, but I have to iterate through it.FindNext quite a few times and each time it runs that line its also activating the row. I really just want something like.
AnswerRow = .Find(nth instance of NextQuestionID).Row
(I have about 50k rows and the count goes to about 20 pretty often so it really takes a while).
I'd appreciate any ideas! Currently my code is working, but it's going to take a good part of the day to complete, and I'll need to run this again at some point!
I ended up finding a way to speed it up a little bit. I think this could help someone so I will share what I've found.
It's not the best solution (I would have preferred to just declare the object locally so my other functions wouldn't change it's value), but at least with this I'm not looping through 20 or so finds every iteration of the Do Loop.
Set Found = Worksheets("MasterScore").Range("j1:j50000").Find(NextQuestionID, LookIn:=xlValues)
If Not Found Is Nothing Then
NextAnswerRange = "j" & 1 & ":" & "j50000" 'The first search will be from the beginning
Do
Set Found = Worksheets("MasterScore").Range(NextAnswerRange).Find(NextQuestionID, LookIn:=xlValues)
NextCell = Found.Address
AnswerRow = Range(NextCell).Row
NextAnswerRange = "j" & AnswerRow & ":" & "j50000"
If LastAnswerRange = NextAnswerRange Then Exit Function 'This would mean we've reached the end.
LastAnswerRange = NextAnswerRange
FindChildren
Loop
End If
End Function
So we know we've already covered our bases with previous ranges since it always finds the immediate next. We just change the range of the search each time and it will find the next value.
A weird thing about this solution is that if you are looking for a value among range 70 -> 50,000 and you have the answer your looking for on row 70, it will actually find the next row (it skips that first one). But, if there aren't any rows past 70 that have the answer, it will actually take the value from row 70. That meant that I couldn't do
NextAnswerRange = "j" & AnswerRow + 1 & ":" & "j50000"
because it would miss some values. Doing it without the + 1 meant at the end of the document I would end up searching the same last value over and over (it would never go back to Found Is Nothing) so I had to put in the check to see if the LastAnswerRange = NextAnswerRange.
I hope this helps someone. I don't think it's the most elegant solution, but it's a lot faster than what I had.

Global Date Variable Works Only for Entered Values

I'm currently working on what should be a relatively simple database, which is very close to being at its end, until I hit the inevitable problem.
I'm using Global Variables and a Form to collect parameters to pass into the Criteria portion of a Query, which works just fine for the first two, which are basic strings and integers.
Then comes the dates, which work, so long as you chose a date from the DatePicker that is entered into the query.
For example, if the query field holds 6/1/2014, 6/3/2014, and 6/8/2014, and the date 6/5/2014 is picked, the form will crash and go blank, though if you pick 6/8/2014, it'll go on as it should.
I had tried a variety of different forms of the code, but in the most basic form I simple have:
Between Get_Global('GBL_Start_Date_ID') AND Get_Global('GBL_End_Date_ID')
I'm not sure if I should be limiting the DatePicker based on the values entered in the query, or if there's a more robust way of going about this, or maybe I just completely missed a simple checkbox.
EDIT
My code for the Global Variables looks like this:
Option Compare Database
Global GBL_Start_Date_ID As Date
Global GBL_End_Date_ID As Date
Global GBL_Customer_ID As Long
Global GBL_Engineer_ID As Long
Public Function Init_Globals()
GBL_Start_Date_ID = #6/1/2014#
GBL_End_Date_ID = #6/30/2014#
GBL_Customer_ID = 1
GBL_Engineer_ID = 1
End Function
Public Function Get_Global(gbl_parm)
Select Case gbl_parm
Case "GBL_Customer_ID"
Get_Global = GBL_Customer_ID
Case "GBL_Engineer_ID"
Get_Global = GBL_Engineer_ID
Case "GBL_Start_Date_ID"
Get_Global = GBL_Start_Date_ID
Case "GBL_End_Date_ID"
Get_Global = GBL_End_Date_ID
End Select
End Function
And I just add a simple line to the AfterUpdate event of the ComboBoxes and TextBoxes to assign the variable:
GBL_Engineer_ID = Me.EngineerSelection
Thanks in advance,
Aaron
You can do two things. Fix the query as it is written or make it much more robust.
To fix it as written
Between "#" & Get_Global('GBL_Start_Date_ID') & "#" AND "#" & Get_Global('GBL_End_Date_ID') & "#"
OR
change your Get_Global function
Public Function Get_Global(gbl_parm)
Select Case gbl_parm
Case "GBL_Customer_ID"
Get_Global = GBL_Customer_ID
Case "GBL_Engineer_ID"
Get_Global = GBL_Engineer_ID
Case "GBL_Start_Date_ID"
Get_Global = "#" & GBL_Start_Date_ID & "#"
Case "GBL_End_Date_ID"
Get_Global = "#" & GBL_End_Date_ID & "#"
End Select
End Function
You are correctly specifying that the values of GBL_Start_Date_ID and GBL_End_Date_ID are dates by using #s when you create them however when you use them in your query they appear without them. You can prove to yourself this is what is happening by typing ?#1/1/2014# into the immediate window. The date is printed as 1/1/2014 which when used in your query, makes Between 6/1/2014 AND 6/30/2014 which is a syntax error.
To make things all that much better you need to parameterize this part of your query. Change this
Between Get_Global('GBL_Start_Date_ID') AND Get_Global('GBL_End_Date_ID')
to this
Between pStartDate AND pEndDate
Before you call your query you need to do your usual checks: are either of these null? is pStartDate < pEndDate?
By performing these checks and parameterizing this you ensure that you never end up with a query like this. Calling your query means you need to need to populate the parameters with DAO or ADO.
Between AND