Using a global var in an SQL query - sql

I have an access project in wich I use a global variable across all the forms to show what user is logged in.
Public activeUser As String
On one of the forms I want show data depending on who is logged in. there are several fields on the form, so I want to use a query as data source across the whole form.
Now here is my problem:
I tried to make a query that uses the value in activeUser to look up all the values that the active user should be able to see:
SELECT WBS_Id,
Verantw,
Commentaar
FROM tbl_New_WPE_User
WHERE UserName LIKE activeUser
Why does this not work? and How can I make it work?

One option would be to create a VBA function to return the value of the global variable. For example
Public Function GetActiveUser() As String
GetActiveUser = activeUser
End Function
Then you could use the function in a saved query like
SELECT WBS_Id,
Verantw,
Commentaar
FROM tbl_New_WPE_User
WHERE UserName LIKE GetActiveUser()
However, in this particular case I would be inclined to get rid of the global variable and just call the function to get the current user (i.e., the code you used to populate the global variable). I doubt that the extra overhead of retrieving the value each time (e.g., by getting the .Username property from a WScript.Network object) would amount to very much, and if it did turn out to be an issue then you could always consider using a Static variable inside your function to cache the value.

i guess SQL is written in VBA code in form of string:
Public activeUser As String
dim tmpSql As String
tmpSql = "SELECT WBS_Id, Verantw, Commentaar FROM tbl_New_WPE_User WHERE UserName LIKE activeUser"
if so, then you should do the following:
tmpSql = "SELECT WBS_Id, Verantw, Commentaar FROM tbl_New_WPE_User WHERE UserName LIKE " & activeUser & "*"
where * in Access is the equivalent for % in SQL Server
Now, if the SQL statement is written in an Access Query, then it's not possible to use VBA variable activeUser

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.

How to find out where a function is being called from in MS Access?

I am working on an MS Access database application that was created by someone else. There is one particular line of code (a Function) that will randomly get called and I have no idea why it is being called or what it does. I have searched (ctrl+F) the entire project for something that calls this function but I can't find it. How can I find out why this Function is being called? (See below). Thank you!
Public Function Concat(strIOSC As String, strFeature As String) As String
Static strLastIOSC As String
Static strFeatures As String
If strIOSC = strLastIOSC Then
strFeatures = strFeatures & ", " & strFeature
Else
strLastIOSC = strIOSC
strFeatures = strFeature
End If
Concat = strFeatures
End Function
If you have only searched the scripts and modules, then your scope is too narrow.
A public function like this can also be used in expressions, so you need to check queries, reports, form controls, macros, and possibly even tables if you use calculated fields. Depending on the size of the database, and how often the function is called, you can either search manually in a targeted way or possibly use a public sub to output something searchable. This sub can get you started. I think it outputs every possible location for expressions. Unfortunately, each object will have its own text file which will need to be searched separately unless you build a sub to do that too.
As for what your function does, it looks like it logs each input using the Static strLastIOSC variable, compares to the arguments passed on the second function call, and if they match it concatenates the two strFeature inputs together and outputs the result.
So basically the first argument tells the function whether this is the beginning of a new concatenation instance, or the continuation of an existing instance. The second argument is the item to be concatenated.
The Static keyword means that the value is stored even after the function runs so it can compare the last call with the current call to determine whether to add the second argument to the one saved from before, or clear the memory and prepare for a new concatenation.
Given its design, it's probably being used in a query/report/form, where strIOSC is likely a primary key field or a field in a GROUP BY.

MS Access correctly utilizing a string variable within DLookup

I am attempting to replace the domain parameter of DLookup with a variable, the intent being a single place to make a change if one is required. This is how I am declaring the variable:
Dim MnMnuSettingTbl As String
MnMnuSettingTbl = "'tblMainMenu'"
This is the original segment where the variable is to be used:
Me.MainMenuChoiceOne.Caption = DLookup("BtnText", "tblMainMenu", "ID = 1")
I wish to replace the domain criteria "tblMainMenu" with the variable, but when I attempt to do so it either does not compile, or I get an error message stating the table can not be found. I have reviewed several articles on this matter, and I am gathering I am not passing the variable correctly, via the improper use of single or double quotes. I'm rather embarrassed, so at this point I am looking for the correct way to either format the variable or the correct way to use it within the DLookup context.
The variable must contain the same constant string as you currently have in the DLookup.
MnMnuSettingTbl = "tblMainMenu"
Me.MainMenuChoiceOne.Caption = DLookup("BtnText", MnMnuSettingTbl , "ID = 1")
Single quotes would be needed for string parameters in the WHERE clause, e.g.
strTextID = "'QD42'"
x = DLookup("foo", "bar", "TextID = " & strTextID)

Microsoft Access VBA: need to get sql representation programmatically from existing query

I need to be able to get the sql "property" from an existing query. So for example I could define strRS as:
strRS = Me.RecordSource '.RecordSource returns the name of a query
Then pass that value to as yet undefined function UnknownFunction(strRS) that takes strRS as a value:
strSQL = UnknownFunction(strRS)
Then the desired output, strSQL would be the original SQL string that defines the query pointed to by the form's "RecordSource" property.
The closest I've been able to get is that there may be a solution using QueryDef, but that is for queries made on the fly? What should the UnknownFunction be?
Once I have the strSQL string then I can extract from it to make a related query.
Ok, it is trivial IF one doesn't make it too complicated. I probably was getting the wrong answer at first because I was confusing "QueryDefs" with "QueryDef", which I should have known.
So without further ado, the full working code is:
Function FCN_QClip(strQRY As String) As String
qds = CurrentDb.QueryDefs(strQRY).SQL
FCN_QClip = qds
End Function
?FCN_QClip("QueryName") will yield the desired result in the immediate window for an existing query. Thanks to Nathan.
The solution may also be found at Social MSDN.

How to send a query string from function

I'm having a hard time coming up with a good title, but i hope i can explain the situation better. I currently have a query with a criteria which is ("11:00 - 21:00" Or "11:01 - 21:00"), this works perfectly fine when executed, however i will need this criteria in multiple queries therefore i decided to come up with function like below
Function timeIntervals()
timeIntervals = "11:00 - 21:00" & " Or " & "11:01 - 21:00"
End Function
and call it in each query, therefore each time i require to modify this string i can do it through that one instance, however when running this string above it does not function, im assuming its caused by the quotes on the Or, ive tried triple quotes """ and chr(34), however it doesn't work, can someone suggest a work around thank you!
As Remou indicated, you won't be able to get this to work. If you really want to do the check via a VBA function, you could write something like this:
Function timeIntervals(Value) As Boolean
If Value = "11:00 - 21:00" Or Value = "11:01 - 21:00" Then
timeIntervals = True
End If
End Function
Pass the value you want to check, and if the resulting function is true you then display the row. Something like: where timeIntervals(myvalue) = true.
Probably the best solution though is to make a table for the timeIntervals. Then in your query simply write something like:
Where MyValue IN(Select timeValue from timeIntervals)
Using this latter method you can update the table which will update the results for all users, and doesn't require a re-release of your front-end.
No matter what you do with quotes, that is not going to work, because Or will be returned as a string, not the boolean Or that you want. You could use a hidden form with two textboxes, then you can say:
WHERE timeIntervals = Forms!MyForm!Text1 Or Forms!MyForm!Text2
as long as the form remains open, your queries and any forms or reports based on them will work, furthermore, it will be very easy to change the intervals without modifying code.