Passing SQL parameters containing spaces or hyphens - vba

A) I'm collecting data from legacy applications; data elements are containing spaces and hyphens (CBR - CR - 22 - 2) or (CBR-CR-22-2)
B) In VBA, when building function and passing SQL parameters with those data elements, the code is generating errors (many!)
C) I narrowed down to identify that ALL errors were caused by the format of the data elements
D) The data element causing the problem is a PRIMARY KEY in about 30 tables and is generated by the legacy applications
(see code) I tried syntax:
A) strDataElm
B) [strDataElm]
C) & """ & strDataElm & """
strSourceSql = "SELECT " & strSourceFld & " FROM " & strSourceTbl & " WHERE " & strSourceFld & " = " & strDataElm
in the immediate window it gives
SELECT NumeroCtl FROM tblLnkCtrl WHERE RISKID = CBR - CR - 22 - 2
In a ideal world, I'd like the strDataElm being passed as is i.e. CBR - CR - 22 2 or without spaces CBR-CR-22-2; removing the hyphens would bring issues because the data is a primary key and reused in other applications..

As it is mentioned it is better to use parametrized queries, but I know - way to concatenate string is too pleasurable.
Try this:
strSourceSql = "SELECT " & strSourceFld & " FROM " & strSourceTbl & " WHERE [" & strSourceFld & "] = [" & strDataElm & "]"
if you pass the field reference
And this, if you pass the value itself
strSourceSql = "SELECT " & strSourceFld & " FROM " & strSourceTbl & " WHERE " & strSourceFld & " = " & "'" & strDataElm & "'"

Related

Access asking me to enter a parameter value

I'm running an SQL query through VB in Microsoft Access for form to add records to a table. However, it keeps asking me to insert parameter value, when they are already present in the form.
Private Sub AddPart_Click()
Dim strSQL As String
strSQL = "INSERT INTO Part VALUES (" & Me.IdPartPrimary.Value & ", " & Me.NamePartPrimary.Value & ", " & Me.BrandPartPrimary.Value & ", " & Me.ModelPartPrimary.Value & ", " & Me.FunctionPartPrimary.Value & ", -1, " & Me.FatherPartPrimary.Value & ", " & Me.ProviderPartPrimary.Value & ", " & Me.AmountPartPrimary.Value & ");"
DoCmd.RunSQL strSQL
End Sub
I already checked for spelling mistakes and there were none. Also, this happens with every field. If I don't insert a parameter value and cancel instead, the record still gets added, only after I close and reopen the table lots of times.
If fields are text type, need text delimiters - apostrophe will serve. I assume comboboxes have a number value from a hidden foreign key column. Value property does not need to be specified as it is the default.
With Me
strSQL = "INSERT INTO Part " & _
" VALUES (" & .IdPartPrimary & ", '" & _
.NamePartPrimary & "', '" & .BrandPartPrimary & "', '" & _
.ModelPartPrimary & "', '" & .FunctionPartPrimary & "', -1, " & _
.FatherPartPrimary & ", " & .ProviderPartPrimary & ", " & .AmountPartPrimary & ")"
End With
AFAIK, Access cannot execute multi-action SQL statements but SQL injection is still possible. If you want to explore use of Parameters in VBA, review How do I use parameters in VBA in the different contexts in Microsoft Access?
Another alternative to avoid SQL injection is to open a recordset, use its AddNew method to create a new record, and set value of each field. DAO.Recordset AddNew

Filter Access form by multiple filters

I have a form that filters a database using multiple filters. However all filters need to be entered in or have a value for the table to be filtered correctly.
I would like to be that not all inputs are required to filter the table.
I'm not sure if thats worded correctly.
Please see what I have tried so far.
DoCmd.ApplyFilter _
"select * from SageOrderLine_Live where " & _
"[PromisedDeliveryDate] = " & Format(Me.DateFrom, "\#mm\/dd\/yyyy\#") & "
and " & _
"[CustomerAccountNumber] = """ & Me.CustomerAccountNumber & """" & " and
" & _
"[Code] = """ & Me.Codes & """" & " and " & _
"[AnalysisCode1] = """ & Me.Analysis & """" & " Or " & _
"[AnalysisCode2] = """ & Me.Analysis & """" & " Or " & _
"[AnalysisCode3] = """ & Me.Analysis & """"
Consider using a parameterized query avoiding concatenation and quote punctuation by directly referencing form controls. Use such a query in form RecordSource calling NZ to assign missing search parameters to column itself. Logically this will render all search parameters optional. Do note below does not considsr NULL values.
SQL (save as stored query object to be used as form's RecordSource)
SELECT * FROM SageOrderLine_Live
WHERE [PromisedDeliveryDate] = NZ(Forms!myform!DateFrom, [PromisedDeliveryDate])
AND [CustomerAccountNumber] = NZ(Forms!myform!CustomerAccountNumber, [CustomerAccountNumber])
AND [Code] = NZ(Forms!myform!Codes, [Code])
AND [AnalysisCode1] = NZ(Forms!myform!Analysis, [AnalysisCode1])
AND [AnalysisCode2] = NZ(Forms!myform!Analysis, [AnalysisCode2])
AND [AnalysisCode3] = NZ(Forms!myform!Analysis, [AnalysisCode3])
VBA
Me.Form.Requery

Why is this access query taking so long?

I wrote an access client to do comparisons against two excel files. It loads the two excel files that are being compared into temporary tables and evaluates them based on the two queries show below.
There are two queries because sometimes one of the excel files will only have one name column. Basically the user inputs the name of the columns being compared and we change the query based on that.
The first query, cQueryFull, works perfectly and very fast (over 100k records in just a few seconds). The second query, cQueryPart, works as intended (in terms of comparison) but has never completed on tables with more than 5,000ish records. It ends up hanging for hours and I am forced to close the program.
I don't understand why one query is so much faster than the other and I was hoping someone might be able to help me figure it out and possibly fix the second query. The part of my access client that is creating the query is below:
If chkOneColumn.Value = 0 Then
' Construct Comparison Query
qString = "SELECT OriginalFile." & txtOriginalFirst.Value & " as OriginalFirstName, OriginalFile." & txtOriginalMiddle.Value & " as OriginalMiddleName, OriginalFile." & txtOriginalLast.Value & " as OriginalLastName, WorkingFile." & txtWorkingFirst.Value & " as WorkingFirstName, WorkingFile." & txtWorkingMiddle.Value & " as WorkingMiddleName, WorkingFile." & txtWorkingLast.Value & " as WorkingLastName " _
+ "FROM OriginalFile, WorkingFile " _
+ "WHERE (OriginalFile." & txtOriginalFirst.Value & " not like WorkingFile." & txtWorkingFirst.Value & " or OriginalFile." & txtOriginalMiddle.Value & " not like WorkingFile." & txtWorkingMiddle.Value & " or OriginalFile." & txtOriginalLast.Value & " not like WorkingFile." & txtWorkingLast.Value & ") " _
+ "and OriginalFile." & txtOriginalAddress.Value & " = WorkingFile." & txtWorkingAddress.Value & " " _
+ "and OriginalFile." & txtOriginalDOB.Value & " = WorkingFile." & txtWorkingDOB.Value & " "
' Open the record set
Set db = CurrentDb
Set qd = db.CreateQueryDef("cQueryFull")
With qd
.ReturnsRecords = True
.sql = qString
End With
DoCmd.OpenQuery "cQueryFull"
ElseIf chkOneColumn.Value = -1 Then
' Construct Comparison Query
qString = "SELECT OriginalFile." & txtOriginalFirst.Value & " as OriginalName, IIF(WorkingFile." & txtWorkingFirst.Value & " is null, '', WorkingFile." & txtWorkingFirst.Value & ") + IIF(WorkingFile." & txtWorkingMiddle.Value & " is null, '', ' '+WorkingFile." & txtWorkingMiddle.Value & ") + IIF(WorkingFile." & txtWorkingLast.Value & " is null, '', ' '+WorkingFile." & txtWorkingLast.Value & ") as WorkingName " _
+ "FROM OriginalFile, WorkingFile " _
+ "WHERE (OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingFirst.Value & "+'*' or OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingMiddle.Value & "+'*' or OriginalFile." & txtOriginalFirst.Value & " not like '*'+WorkingFile." & txtWorkingMiddle.Value & "+'*') " _
+ "and OriginalFile." & txtOriginalAddress.Value & " like WorkingFile." & txtWorkingAddress.Value + " " _
+ "and OriginalFile." & txtOriginalDOB.Value & " like WorkingFile." & txtWorkingDOB.Value & " " _
' Open the record set
Set db = CurrentDb
Set qd = db.CreateQueryDef("cQueryPart")
With qd
.ReturnsRecords = True
.sql = qString
End With
DoCmd.OpenQuery "cQueryPart"
End If
Can anyone identify the problem with my query? In case it matters, I have already tried indexing the tables before the query is built and executed. Any help would be greatly appreciated!
It's hard to tell, but I suspect the problem is with the cross joins and the amount of predicates (and type of predicates) in the WHERE clause(s).
Joining two tables like you're doing tends to create a very large set that the WHERE clause will then have to run through. Furthermore, the LIKE operator in a JET/ACE query is probably the slowest comparison operator that there is. Especially LIKE with a leading wildcard (*).
Sometimes there's just no getting around it, but sometimes it's actually faster to load pre-queried portions into (yet another) temp table and run further queries against that data.
Is there any way you can simplify your WHERE clause, or identify the predicates in distinct batches in such a way that you can run a more straighforward query first, then further process those results? (I suggest possibly writing to temp tables and further querying because subqueries are optimized and don't necessarily guarantee that the "sql logic" you write it as will be how it's actually run).

DATE Variable not inserting values properly

I have a macro that opens a MS Project file and copies the content itself in an Access table. I make it through Excel because afterwards I need to make some queries and copy the results into some cells.
This code below creates or drops the table:
Dim dbX As DAO.Database
If Err.Number = 0 Then
dbX.Execute ("DROP TABLE " & dbName & ";")
End If
dbX.Execute ("CREATE TABLE " & dbName & " ([ID] INTEGER, [TaskID] INTEGER, [Milestone] TEXT(3), [TaskName] TEXT(255), " & _
"[pComplete] TEXT(10), [Start] DATE, [Finish] DATE, [BaselineStart] DATE, [BaselineFinish] DATE, " & _
"[ActualStart] DATE, [ActualFinish] DATE);")
Err.Clear
This fills the table using the project fields:
dBquery = "INSERT INTO " & tName & "(ID, TaskID, Milestone, TaskName, pComplete, Start, Finish, BaselineStart, BaselineFinish, " & _
"ActualStart, ActualFinish)" & _
" VALUES (" & t.ID & ", " & t.UniqueID & ", '" & t.GetField(pjTaskMilestone) & "', '" & t.Name & "', '" & t.GetField(pjTaskPercentComplete) & _
"', " & RetrieveDate(t.Start) & ", " & RetrieveDate(t.Finish) & ", " & RetrieveDate(t.BaselineStart) & ", " & _
RetrieveDate(t.BaselineFinish) & ", " & RetrieveDate(t.ActualStart) & ", " & RetrieveDate(t.ActualFinish) & ");"
dB.Execute dBquery
RefreshDatabaseWindow
This is the function used to retrieve the date fields:
Function RetrieveDate(D As Variant) As Variant
If D = "NA" Then
RetrieveDate = "NULL"
Else
RetrieveDate = "#" & D & "#"
End If
End Function
The problem that I have is that when the code finds an ambiguous date, uses the American format, so when I try to run queries, the results are not correct.
For example, here I have a task with its dates and everything:
Whatever the date format I use it spins the date or it just doesn't insert the dates into the DB.
For example, in this table, the dates are inserted in decimal format. The same task in the database is:
In this image above we can see fewer fields because I've just taken the ones that I need.
So, if for example I make a query to retrieve the date in 'dd/mm/yyyy' format this same task, I get:
SELECT FORMAT(Start, "dd/mm/yyyy"), FORMAT(Finish, "dd/mm/yyyy")
FROM ow18_072014
WHERE TaskID = 202;
I have tried to convert the format to yyyy/mm/dd but the dates are not pasted into the table.
Another conversion I have tried is to change date format from Project but now Access changes some dates without any sense: a date equal to 20 Jun 2014 in MS Project becomes 15/11/2013 in MS Access.
You do not give us much information, and in the future, if you want people to actually have a chance of helping you, you have to put more effort in your question: give us some code you tried, some data example, etc.
Anyway, the issue is that by default, Access interprets literal dates as #mm/dd/yyyy#, except when it's unambiguous, like #25/12/2014#.
There are 2 ways to solve this issue: if you pass a litteral date to Access, use the #yyyy/mm/dd# ISO format instead because it's unambiguous and it will work in every locale.
Alternatively, convert your date to a decimal value and pass that to your Access date field instead, like CDec(myDate), will pass something like 41851.3465625 to Access and it will work.
The GetField method of the Task object returns a string value. For date fields, it returns the value in the format selected by the user (or set by the DefaultDateFormat property of the application object).
The simplest solution is to use the explicit properties of the Task object instead of the GetField method.
Modify your SQL statement to something like this:
dBquery = "INSERT INTO " & t.Name & "(ID, TaskID, Milestone, TaskName, pComplete, Start, Finish, BaselineStart, BaselineFinish, " & _
"ActualStart, ActualFinish)" & _
" VALUES (" & t.ID & ", " & t.UniqueID & ", '" & t.Milestone & "', '" & t.Name & "', '" & t.PercentComplete & _
"', " & RetrieveDate(t.Start) & ", " & RetrieveDate(t.Finish) & ", " & RetrieveDate(t.BaselineStart) & ", " & _
RetrieveDate(t.BaselineFinish) & ", " & RetrieveDate(t.ActualStart) & ", " & RetrieveDate(t.ActualFinish) & ");"

How to simplify this insert statement

So I'm trying to insert 120 rows into a new table and it keeps throwing "Query too complex" errors at me. It works fine upto 90 rows.
This is the query:
SQL = "INSERT INTO " & newtable & " ([" & sourceQ & "_" & master & "],
[" & sourceQ & "_" & fld.Name & "])" & " SELECT
[" & sourceQ & "." & master & "], [" & sourceQ & "." & fld.Name & "]"
& " FROM " & sourceQ
I have tried playing with where clauses adding WHERE [" & sourceQ & ".Expr1] like ('Field09?') but it still throws those errors.
I even tried a simple one that should work like WHERE [" & sourceQ & ".Expr1] = 'Field001', which should just be 1 row, but it still throws the error.
Anyone have any ideas?
edit: debug
INSERT INTO tblCalc ([qJoinKeyAndStudent_<>], [qJoinKeyAndStudent_0 1 0 1])
SELECT [qJoinKeyAndStudent.<>], [qJoinKeyAndStudent.0 1 0 1]
FROM qJoinKeyAndStudent WHERE [qJoinKeyAndStudent.Expr1] like ('*09#')
While Access is capable of handling spaces in field and table names, you need to encapsulate both the field and table names in separate brackets:
INSERT INTO tblCalc ([qJoinKeyAndStudent_<>], [qJoinKeyAndStudent_0 1 0 1])
SELECT [qJoinKeyAndStudent].[<>], [qJoinKeyAndStudent].[0 1 0 1]
FROM qJoinKeyAndStudent WHERE [qJoinKeyAndStudent].[Expr1] like ('*09#')
Does that work?