DateAdd + DLookup - vba

I am requesting some guidance to fix this problem I have been having while trying to edit the "AfterUpdate" event in my database. It seems to work fine on my local machine but when I try to implement it in the network database it doesn't work properly (occasionally puts in a random date in one of the fields, doesn't erase the date when I supply a new ID, etc.)
Here is the VBA Code I have:
Private Sub provider_surveyID_AfterUpdate()
provider_survey_dueDate = DateAdd("ww", 2, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
provider_survey_reminder2weeks = DateAdd("ww", 4, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
provider_survey_reminder4weeks = DateAdd("ww", 6, DLookup("completed_on",
"qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID))
End Sub
The query is correct, joining the Survey ID to the appropriate participant to determine the original "completed_on" date that is used in the DateAdd functions.
Can you see any reason why it would not work as it does on local - removing dates when entering IDs currently not in use? Also, think it would be wise to use Nz(provider_surveyID,0) in this instance? I haven't implemented it yet as I wanted to make it work appropriately as it does on my local with no issues whatsoever - I enter for the ID, it populates; I enter 20 (not in use yet), it makes all dates null again.

Dlookups can be slow and tricky to use, it will also return random values when the Criteria isn't entered. I'm not sure on how your form is put together (I'm assuming it's a form), and this may be a partial answer:
Private Sub provider_surveyID_AfterUpdate()
Dim dtComplete as Date
If IsNull(provider_serveyID) then
provider_survey_dueDate=""
provider_survey_reminder2weeks=""
provider_survey_reminder4weeks=""
Else
dtComplete = DLookup("completed_on","qry_ProviderSurveyInfo", "provider_surveyID=" & provider_surveyID)
provider_survey_dueDate=DateAdd("ww",2,dtComplete)
provider_survey_reminder2weeks=DateAdd("ww",4,dtComplete)
provider_survey_reminder4weeks=DateAdd("ww",6,dtComplete)
End if
End sub

Related

MS Access - SQL append query behavior is erratic

I've been working on an Access database for the last couple weeks, and it's my first project with the tool. Dealing with append queries seems to have become an utter nightmare, and is incredibly frustrating. Even more so because it seems to have simply stopped working in any consistent manner overnight.
The SQL query that I have written goes thus:
PARAMETERS noteDetails LongText, noteTime DateTime, srcUserID Long;
INSERT INTO tblNotes (NOTE_DETAILS, NOTE_TIME_CREATED, NOTE_SOURCE_USER)
VALUES (noteDetails, noteTime, srcUserID)
In tblNotes:
NOTE_ID is an AutoNumber
NOTE_DETAILS is a Long Text
NOTE_TIME_CREATED is a Date/Time
NOTE_SOURCE_USER is a Number
The way that I'm running this query is through VBA:
Set qdf = CurrentDb.QueryDefs("qerApndNote")
qdf.Parameters(0).Value = txtDetails.Value
qdf.Parameters(1).Value = Now()
qdf.Parameters(2).Value = getCurrentUserID()
qdf.Execute dbFailOnError
qdf.Close
Set qdf = Nothing
' Where CurrUserID is a global long
' txtDetails.Value is a textbox's contents
' Now() is the VBA built-in function to return a date/time combo
I have attempted to run this query manually from the navigation bar, and it works fine when done in that manner.
However, running it from VBA has resulted in such things as there being no time / date inserted, sometimes a user ID is not inserted, sometimes both, sometimes even the details text is missing.
What is it that I'm missing? Is there any general advice for users of MS Access to follow that I am not? I'm aware that NOTE is a restricted word in Access, but I really don't think that should apply here, right?
Thanks in advance!
EDIT: The form that I'm passing data from is called frmNewNote, and there is a control in it named txtDetails. It's just a regular textbox. Don't really know what else to share about that.
The getCurrentUserID function is in a module, modGlobal:
Public CurrUserID As Long
Public Function getCurrentUserID() As Long
getCurrentUserID = CurrUserID
End Function
Public Function setCurrentUserID(CurrID As Long)
CurrUserID = CurrID
End Function
It's about as barebones as you can get, really. And there is never a circumstance that you'll get to the form before SetCurrentUserID has been called during your... session? There's a login form involved.
#Andre's code for logging:
0 noteDetailsText This is a note test
1 noteTimeCreated 9/6/2017 10:28:45 AM
2 srcUserID 1
As for my architecture, um, it's just the single database file right now, on the desktop. The entire function/sub is run when you click a button, btnEnter. It does some other stuff before it gets to the SQL statement bit - checks for null values and prompts user for entries if that's the case.
I just remembered something:
MS Access 2013 calling insert queries from VBA with strange errors
You have a LongText parameter. These don't really work. See also https://stackoverflow.com/a/37052403/3820271
If the entered notes will always be <= 255 characters, change the parameter to ShortText.
If the text can be longer, you'll have to use either SunKnight0's approach with a concatenated INSERT statement.
Or use a Recordset and its .AddNew method, which will be a similar amount of code to your current solution, but also be completely safe from injection or formatting issues.
You are doing way more work than you have to. All you need is:
DoCmd.RunSQL("INSERT INTO tblNotes (NOTE_DETAILS, NOTE_TIME_CREATED, NOTE_SOURCE_USER) VALUES ('" & Me.txtDetails & "',Now()," & CurrUserID & ")")
Note the change from txtDetails.Value to Me.txtDetails which is what may have been messing you up. This of course assumes the code runs in the form's context, otherwise you have to get he value of the text field using a reference to the form.
The only other thing to consider is making sure Me.txtDetails does not have any single quotes, so probably use Replace(Me.txtDetails,"'","''") instead.
That way you can also replace DoCmd.RunSQL with MsgBox to troubleshoot the exact query.

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.

Change AllowEdits property based on Entry Date

I have number of split forms in an Access 2016 database which are regularly used by various employees for data entry. It is important that users are able to see old records but are not able to edit them.
However, I want to allow users to edit records that have been made that day in case they notice an error in a record they have just entered.
My current approach is to set the AllowEdits property on the form to yes, then to override it for entries made on the same day with the following code
Private Sub Form_Load()
If (Me![rec_date] < Now()) Then
Me.AllowEdits = False
Else: Me.AllowEdits = True
End If
End Sub
I think there is a problem with the If criteria though, as all this currently does is prevent editing of all records.
For background [rec_date] refers to the date on which the record was entered.
Couple of things:
Use the "Current" event instead if you're working with record changes. Form Load only works when the form itself opens. If you change records it will do nothing for you.
Might as well move that Else statement down to the next line and indent correctly for readability.
Your conditional statement doesn't quite match what you told me. You're trying to match a specific day but you use a date time (now()) instead of date. You also use less than instead of equals. I would suggest using equals and the date function (note: doesn't use () and returns only the date portion of now() ).
Hopefully that helps! Here's my suggested code:
Private Sub Form_Current()
' Only allow editing of records created today.
If (Me![rec_date] = Date) Then
Me.AllowEdits = True
Else
Me.AllowEdits = False
End If
End Sub
An even shorter form as suggested by Mat's Mug
Private Sub Form_Current()
Me.AllowEdits = Me![rec_date] = Date ' Only allow editing of records created today.
End Sub

VB.Net and handling dates within Grid Controls - better way?

While I have my app running, I question the methodology, and wondering if there’s a “better way”…
Overall design is to allow editing 200-300 records from a gridview (phase1) using VB.Net. The database itself is on SQL Server. There are a number of columns a user will enter into an “application”, and there are several columns that will be edited/maintained by “office users”, if you will. There are several dates involved in this ongoing maintenance, and that’s where the first of my questions revolves.
I have found “solutions” on the internet that got the code working, but am questioning them…
Problem #1 I ran into – dates are NULL in the database, and in trying to read them in using a SqlDataReader led to errors (cannot assign NULL to a Date object). Ok, that led into using a ternary operator to use “IsDBNull”, and either assign the value read from the DB, or to assign DateTime.MinValue. Problem “solved”…
Problem #2 – using the above method now shows dates that are the minimum VB date value – showing actual dates in the fields the user is to edit – definitely not “user friendly”, nor what I want. The only solution to this issue was:
Convert dates from Date or DateTime objects into String objects. This would then allow me to be able to assign an empty string to the gridview in the case where the date was originally NULL in the DB, which had to be transformed into DateTime.MinValue (which could be tested), and then another ternary operator to assign either “ToString” conversion, or an empty string to the gridview field.
Ok – editing is now accomplished. I added some “ScriptManager.RegisterStartupScript” commands to allow testing the validity of the dates the user enters – all is well.
Problem #3 (or 4) – I now need to update the database with the data the user entered – PRESERVING THE EMPTY DATE STRINGS – and update the database (using parameters…) with NULLs back in those date columns. However, again – the date is a string, and is empty, so I had to assign to a “MinValue”, first, then another ternary operator to test each date against “MinValue”, and either assign the date, or a DBNull.Value…
Yes, I guess I could have come up with a number of different update strings (including dates in some, excluding in others), depending on whether or not a string/date was empty or not... But that will only lead to future bugs, so, I guess I’ll be keeping a series of ternary operators.
So, the code for beginning the edit process looks something like:
While sdr.Read
Dim _date1 As Date = If(IsDBNull(sdr("date1")), DateTime.MinValue, sdr("date1"))
.
.
.
‘ Now add them to a List of my Class:
appsList.Add(New AppClass(… _
If(_date1 = DateTime.MinValue, " ", _date1.ToString("MM/dd/yyyy")), _
… )
Now to get the data back from the gridview to update the database:
Dim _date1 As Date
' see if we can convert the various dates...
Try
' see if empty…
If ((CType((row.Cells(19).Controls(0)), TextBox)).Text).Length < 2 Then
_date1 = DateTime.MinValue
Else
_date1 = DateTime.Parse((CType((row.Cells(19).Controls(0)), TextBox)).Text)
End If
Catch ex As Exception
ErrFlag = True
ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "alert(‘Date1 Date is not valid - enter as MM/DD/YYYY');", True)
End Try
.
.
.
Dim sql As String = "UPDATE [foo_bar].[dbo].[bar_foo] set date1=#Date1, …….)
cmd.Parameters.AddWithValue("#Date1", If(_date1 = DateTime.MinValue, DBNull.Value, _date1))
Honestly, all this conversion back and forth seems like it’s going to lead to bugs or errors at some point.
So – is this the “best” method for handling this? There isn’t a cleaner way?
If your using winforms then you can handle the Format and parse of the databindings. I haven't tried it on a Gridviewtextbox but worst case you can use a custom cell template and a textbox with format and parse handlers. The code would be something like this:
mybinding = New Binding("text", DataSet1, "table1.datefield")
Me.DataGridTextBoxColumn1.TextBox.DataBindings.Add(mybinding)
AddHandler mybinding.Parse, AddressOf StringToDateTime
AddHandler mybinding.Format, AddressOf formatdate
Private Sub StringToDateTime(ByVal sender As Object, ByVal cevent As ConvertEventArgs)
If cevent.Value.GetType().Equals(GetType(String)) And _
cevent.DesiredType Is GetType(DateTime) Then
If cevent.Value <> "" Then
' Make sure matches format in format funtion
cevent.Value = DateTime.Parse(String.Format(cevent.Value, "MMM d, yy"))
Else
cevent.Value = DBNull.Value
End If
'cevent.Value = DateTime.Parse(String.Format(cevent.Value, "MMM d yyyy")
End If
End Sub
Public Sub formatdate(ByVal sender As Object, ByVal e As ConvertEventArgs)
If e.Value.GetType().Equals(GetType(DateTime)) And e.DesiredType Is GetType(String) Then
' Hard-coded or user-specified
' Make sure matches format in parse funtion
e.Value = Format(e.Value, "d")
End If
End Sub

Remove dot´s from date

I made a program that generates a daily index code.
It gets created from
Employer (everyone has a number from 0-9)
Date of serial code requested
Everything is working fine, but I wannt to remove the dots from the date
I tried things like
date.Text = date.Text.Replace(".""", """")
or
Dim clean as String
clean = myString.Replace(".", "")
But nothing happens
May be I just didnt unterstand the using... If yes, so please help me to find a alternative.
Ok i will try to explain better.
As I lunch it a textbox gets the date of today, the textbox is called date
Ive got a combobox, from there you select the employer. Every employer has a number. For example Andreas is Number 1.
I wannt to do something like:
if combobox1.text = "Andreas" then
dailyCode.text = "1" & date.text
end if
My problem is that the date is written with dots, the daily code should not have dots.
Sorry for my bad English
In your questions Details are still incomplete.still assuming that the date(still i am confused how are you using reserved keyword) is declared as date type itself,consider formatting it with Format function itself.
Try using
Dim s As String = Format(date, "ddMMMyyyy")
hope that helps.