Is there an equivalent to the SUBSTRING function in MS Access SQL? - ms-access

I want to do something like this within an MS Access query, but SUBSTRING is an undefined function.
SELECT DISTINCT SUBSTRING(LastName, 1, 1)
FROM Authors;

You can use the VBA string functions (as #onedaywhen points out in the comments, they are not really the VBA functions, but their equivalents from the MS Jet libraries. As far as function signatures go, they are called and work the same, even though the actual presence of MS Access is not required for them to be available.):
SELECT DISTINCT Left(LastName, 1)
FROM Authors;
SELECT DISTINCT Mid(LastName, 1, 1)
FROM Authors;

I think there is MID() and maybe LEFT() and RIGHT() in Access.

I have worked alot with msaccess vba.
I think you are looking for MID function
example
dim myReturn as string
myreturn = mid("bonjour tout le monde",9,4)
will give you back the value "tout"

I couldn't find an off-the-shelf module that added this function, so I wrote one:
In Access, go to the Database Tools ribbon, in the Macro area click into Visual Basic. In the top left Project area, right click the name of your file and select Insert -> Module. In the module paste this:
Public Function Substring_Index(strWord As String, strDelim As String, intCount As Integer) As String
Substring_Index = delims
start = 0
test = ""
For i = 1 To intCount
oldstart = start + 1
start = InStr(oldstart, strWord, strDelim)
Substring_Index = Mid(strWord, oldstart, start - oldstart)
Next i
End Function
Save the module as module1 (the default). You can now use statements like:
SELECT Substring_Index([fieldname],",",2) FROM table

I used an update query as follows: I added to my access table one empty column for the string element I needed. Then I filled the new column with an update query with this logic in the "UpdateTo" line: "Mid([TABLE].[FIELD],3,1)" as I needed exactly the 3 character of the field. The preceding answers took me here (thanks).

Related

Access-VBA - Compile Error with ConcatRelated - Previously worked

I'm receiving a compile error attempting to run a query using Allen Browne's ConcatRelated function.
Compile error: in query expression 'SELECT MbrNbr, EventIndex, ConcatRelated("EventIndex", "PlayerResults", MbrNbr = 123456)'.
The mystery is I know this executed successfully previously.
Note: This is my first time using MS Access for a project, so it's my first time using Allen's ConcatRelated function. I have to assume there is something obvious I'm missing. I've coded in MS Excel VBA for about 10 years.
I do have a query that is more complex than the example below but I put together this very basic query just to test if there is something amiss with my setup all of a sudden.
I've googled all I can to attempt to resolve this and all code examples seem to show I have it correct.
Setup:
ConcatRelated is saved as a function named Concat_Related_Data. I've read the function name cannot be ConcatRelated.
The simple query receiving the error is:
SELECT MbrNbr, EventIndex, ConcatRelated("EventIndex", "PlayerResults", MbrNbr = 123456)
FROM PlayerResults;
Note: I copied Allen's example and simply edited it with a call to one of my tables. Field MbrNbr is defined as "Number".
Any insights would be greatly appreciated!
After taking a look here http://allenbrowne.com/func-concat.html I saw that the third parameter is defined as a string parameter too (as expected) and not as a boolean.
So I think you should use this:
SELECT MbrNbr, EventIndex, ConcatRelated("EventIndex", "PlayerResults", "MbrNbr = 123456") FROM PlayerResults;
Info: The third parameter of ConcatRelated also is a string here, containing your condition.
In addition to the answer provided by #UnhandledException; where you state:
ConcatRelated is saved as a function named Concat_Related_Data.
I've read the function name cannot be ConcatRelated.
For clarity: the code for the function should be copied "as is" from Allen Browne's site into a new VBA module, without changing the function name.
However, when saving the VBA module, the module should be named something different to ConcatRelated, else you will receive a type-mismatch error when trying to invoke the function.
Note that if you are using the code within SQL code that is represented using a string in VBA, you will need to either escape the double-quotes (to ensure that they remain in the SQL code), or use single-quotes instead, i.e.:
CurrentDb.OpenRecordset("SELECT MbrNbr, EventIndex, ConcatRelated('EventIndex', 'PlayerResults', 'MbrNbr = 123456') FROM PlayerResults")
Or:
CurrentDb.OpenRecordset("SELECT MbrNbr, EventIndex, ConcatRelated('EventIndex', 'PlayerResults', 'MbrNbr = 123456') FROM PlayerResults")

SSIS For Each loop based on records

I want to accomplish a fairly simple task (I'd think).
I have one table with a shiftid (INT), shiftstart (datetime), shiftend (datetime).
I'd like to query that table, then run a query (on an entirely different database) that asks for production (which is calculated in an odd way - requiring three separate queries) using the start and end times, and store that in the original database with the shiftid and a production amount for the shift.
I've tried to do this using a Foreach Loop and a script task that builds a variable that would contain the query, but I'm continually hitting a brick wall there.
Dts.Variables("User::SQLshiftstart").Value = "SELECT value FROM[dbo].[AnalogHistory] WHERE TagName = 'Z_HISTFMZ_P2_0004' AND DateTime = '" & Dts.Variables("User::shiftstart").ToString
I keep getting an error - "Command text was not set for the command object". And googling that error doesn't push me any further down the path.
Help!
Well, I decided to go a different way instead of using a script object to build a variable. I actually created the variable in my SELECT:
SELECT (CONCAT
('SELECT CAST(value AS DECIMAL(10,4)) AS beg FROM [dbo].[AnalogHistory] WHERE TagName = ''Z_HISTDATA_P1_0007'' AND DateTime = '' ',
DateAdd(hh,-6,shiftstart),
' '' AND wwTimeZone = ''UTC'' '))
This way, I avoid having to build an intermediate script object and can directly query based on the variable name in my FOREACH loop.

RunTime Error 2471: Expression as Query Parameter Producing Error

I have a sub in Access 2010 that references a query. They're supposed to run through three columns and find the lowest one. When I run it, I get an error: "The expression you entered as a query parameter produced this error: 'Projects.ProjectID'
Sub:
Private Sub UpdatePriority_Click()
Overall_Priority = DMin("MinvonGeoPri", "qryOverallPriority", "Projects.ProjectId=1")
End Sub
Query:
SELECT
Min(Projects.GeoPavePri) AS MinvonGeoPri
, Min(Projects.StrPri) AS MinvonStrPri
, Min(Projects.SOPri) AS MinvonSOPri
, Projects.ProjectId
FROM
Projects
WHERE
Projects.ProjNo=Activity.ProjNo;
Google suggested that I add quotations around 1, so I changed it to "Projects.ProjectID=" & 1 & "", but it didn't help. I've double checked spelling, field names, and I'm running out of ideas. Any suggestions would be great.
Once you have created a qryOverallPriority from the select statement, referencing the Projects.[ProjectId] field is simply [ProjectId]. In short, you lose the ability to reference the parent table although it could be referenced as qryOverallPriority.[ProjectId] but that is not necessary..
Private Sub UpdatePriority_Click()
Overall_Priority = DMin("MinvonGeoPri", "qryOverallPriority", "ProjectId=1")
End Sub
Any field pulled by a saved query is referenced by how that save query sees it, not from the underlying SQL select statement that made up the saved query. Likewise, aliased fields would be referenced by their aliases; e.g. [ProjectId] and [ProjectId2] for both [ProjectId] fields in a join.
You are also using the aggregate MIN function without a GROUP BY clause. Use the Access front end to make sure that you are getting the results you want. Perhaps something like,
SELECT
Min(p.GeoPavePri) AS MinvonGeoPri
,Min(p.StrPri) AS MinvonStrPri
,Min(p.SOPri) AS MinvonSOPri
,p.ProjectId
FROM
Projects p
WHERE
p.ProjNo=Activity.ProjNo;
GROUP BY p.GeoPavePri, p.StrPri, p.SOPri, p.ProjectId
You should be able to use,
Overall_Priority = DLookup("MinvonGeoPri", "qryOverallPriority", "ProjectId=1")
That is untested. I have not built a full test environment and I have no idea where Activity.ProjNo comes from.

VBA functions not working, returns error

I have a problem that I have been trying to solve for a couple of days with MS Access and a VBA function.
To start I have a table as follows
Name = Team
fields are mostly text bases, unless stated otherwise
ID(autonumber primary key)
Non
Prenom
Location
TeamID (created by concatenting the Nom, Prenom and Location fields)
On my form I would like to extract the partial details entered into the Nom, Prenom, and Location fields. Then pass this back to the Database to enter into the TeamID field for the individual.
The extraction should take the form of
TeamID = mid(Location,0,4) & mid(Prenom,0,2) & mid(Nom,0,2à)
However I realise that I can't put this into the 'controle source' section of the properties for any field.
So after much searching I decided that I should use a function in a separate module (I do this concatenating quite often for creation of 'sensible' index values on a large number of my tables, I find the autonumber primary key not very user friendly, or self explanatory.
So in my database file I created a module (called getInfo) with the public function
Public Function getID() As String
Dim r As String
Dim i As String
i = "Twenty"
Below are some of the options I have tried....
'r = VBA.Strings.UCase$(String:=i) 'turning the value of i to uppercase
getID = r 'returns "TWENTY" as expected
or
'r = VBA.Strings.Mid$("TWENTY", 0, 2)
getID = r 'error and highlights above line?
or
'r = StrReverse(i)
getID= r 'again error and highlights above line
getID = VBA.Strings.Mid$(String:="TWENTY", Start:=0, Length:=2)
End Function
I then opent eh 'execution' window and run the function.
I seem to be only able to convert the value to upper or lower case, any searching or manipulation of the string just gives me a message bow with the following error
Execution Error '5'
argument or procedure call incorrect
(please bear with me I am working on a french terminal and so my translation of this error may not be very acurate).
However all the functions come up correctly when I type them, as do the parameters being passed. when I search the net the info is also the same
http://www.techonthenet.com/excel/formulas/index_vba.php
So I am lost as to where I am going wrong.
I guess I am not declaring the value of my variables correctly, but I can't see why.
This code doesn't work elsewhere (other terminals) either, so I'm sure it must be my error!
But what is it.
I feel that this is a reallybasic problem, but just can't get the function to work when manipulating a string.
Do I need to call this function from a sub only, and not directly, will this be the same on my form page?
I can create a minidatabase with just this code in if required.
You should not need the VBA.String namespace prefix, and the ArgName:= syntax is optional so long as you follow same-order rules for optional paramaters.
Mid$("TWENTY", 0, 2) fails because in VBA strings start at index 1, so Mid$("TWENTY", 1, 2) would return TW

ms-access localization and default boolean values

Our access client generates on the fly SQL inserts, update and delete instructions to be sent on a MS-SQL Server. Most users have the runtime version of Access 2007, and a few use the complete MS-Access version, 2003 or 2007. This morning one of our new users abroad, using a french/complete version of Access 2003, was unable to update data containing boolean fields.
It appeared that these fields are, in the french version of Access, populated with "Vrai/Faux" instead of "True/False" values. The problem was solved by installing the 2007 access runtime.
But I'd like to find a permanent solution, where I'd be able to read from somewhere which localized version of Access is in use and 'translate' the localized True/False values to standard True/False. I already checked the regional settings of the computer without success, so it is somewhere else. Any idea?
EDIT: Following JohnFX proposal, it is effectively possible to convert from local True/False to universal True/False with this simple function:
Function xBoolean(xLocalBooleanValue) as Boolean
if cint(xLocalBooleanValue) = -1 Then
xBoolean = True
endif
if cint(xLocalBooleanValue) = 0 Then
xBoolean = False
endif
end function
EDIT: following #David's comments, I changed the favorite solution. His proposal is smarter than mine.
EDIT: I am getting the Vrai/Faux values by reading the value of a field in a recordset:
? debug.print screen.activeForm.recordset.fields(myBooleanField).value
Vrai
True is NOT FALSE, or NOT 0, in all cases, no matter the localization or the database format.
So, if you replace all tests for True with NOT 0 and all tests for False with =0, then you've avoided the issue of localization of the Access keywords (I'm surprised that VBA and the Jet and Access expression services would not still understand True/False, though), as well as whichever convention your database engine uses for storing Boolean values.
In general, your data access layer ought to be abstracting that away for you. Both ODBC and ADO do it automatically, so you work with the Boolean values you know and it's taken care of for you transparently, in my experience.
I'm also still puzzled about the question, as it sounds like a display/formatting issue, but use NOT 0 and =0 for True and False avoids the problem entirely in all cases.
EDIT: In regard to the function edited into Philippe's question:
Is there a reason you've implicitly defined your function's parameter as a variant? Is that what you mean? If it's passed a Null, it's going error out on the first CInt(), as CInt() can't accept a Null.
Also, there's a logic problem in that in VBA any number but 0 is supposed to return True. It's also completely redundant code. This is simpler and returns the correct result in all cases:
Function xBoolean(xLocalBooleanValue As Vriant) as Boolean
If CInt(xLocalBooleanValue) <> 0 Then
xBoolean = True
End If
End Function
Or, pithier still:
Function xBoolean(xLocalBooleanValue As Variant) as Boolean
xBoolean = (CInt(xLocalBooleanValue) <> 0)
End Function
And to handle Nulls passed in the parameter:
Function xBoolean(xLocalBooleanValue As Variant) as Boolean
xBoolean = (CInt(Nz(xLocalBooleanValue, 0)) <> 0)
End Function
I'm not sure that's necessary in the context you're currently using it, but I always hate writing code where I can imagine a case where it will error out -- even if I know it can't break in its present context, you never know where it might end up getting used, so should you anticipate a condition that can be handled, you should handle it.
Premature optimization?
No -- it's putting a safety lock on a weapon that keeps it from being misused.
(on the other hand, if it took more lines of code to handle the antipated error than the function started out with, I'd think twice about it)
Have you considered using -1/0 (Access is weird about booleans) instead of true/false in your update and delete queries?
Math is the universal language, yaknow.
Also, to avoid having to localize the UI so much, why not use check-boxes instead of a text field for booleans on your UI?
Simple:
Function xBoolean(bool As Variant) As Boolean
xBoolean = Abs(Nz(bool, 0))
End Function