I have a search page that returns results according to the criteria nominated and this works ok when each criteria is OR but when I use AND it returns bad or no results. For example the search criteria might be...
A. Author = ""
B. Subject = ""
C. Keyword = ""
D. Dated = ""
Code:
SELECT *
FROM Table
WHERE Author = '" & strAuthor & "'
AND Subject = '" & strSubject & "'
AND Keyword = '" & strKeyword & "'
AND Dated = '" & strDated & "' "
Here I have used only 4 parameters whereas in fact there are quite a few more. But the example should explain the problem... to make this work I would need to be more specific such as "if A and B" or "B, C and D" but using any parameters that are blank or NULL will not work.
Now I could write in the criteria using a conditional statement like...
SELECT *
FROM Table
WHERE
if strAuthor <> "" then
Author = '" & strAuthor & "'
end if
if strSubject <> "" then
AND Subject = '" & strSubject & "'
end if
and so on, except that writing SELECT strings like this does not work, just produces errors because the select string cannot contain additional code (that has been my finding).
If the options were only a few I could write separate select strings for each combination, but there are more than 10 different criteria which entail more than 3,628,800 combinations!
Is there a solution for this?
Here you are having 2 options:
a) Create a stored procedure and have some default value for all the columns, and in case if user doesn't pass any value, the query would run with the default value for that column.
b) Impose the rule on the front end to always select a value for all the columns.
No stored procedures are needed when using this code:
SQL = "SELECT * FROM Table WHERE ID <> ''"
if len(strAuthor) > 3 then
SQL = SQL & " AND Author = '" & strAuthor & "'"
end if
if len(strSubject) > 3 then
SQL = SQL & " AND Subject LIKE '%" + Replace(strSubject, "'", "''") + "%'"
end if
if len(strKeyword) > 3 then
SQL = SQL & " AND Description LIKE '%" + Replace(strKeyword, "'", "''") + "%'"
end if
if strCatID <> "" then
SQL = SQL & " AND Category = '" & strCatID & "'"
end if
SQL = SQL & " Order By Subject ASC "
The significance of the first line where it requests ID is to serve as a generic placeholder so that all following parameters can be prefixed with "AND".
If a variable is empty it is not included, so only those specified are used.
Related
I have declared variables that store the name of columns from a SQL Table as well as variables that store their corresponding "values to find".
Dim sColumn1 As String
Dim sColumn2 As String
Dim sColumn3 As String
Dim sValue1 As String
Dim sValue2 As String
Dim sValue3 As String
sColumn1 = Sheets(1).Range("A1").Value
sColumn2 = Sheets(1).Range("B1").Value
sColumn3 = Sheets(1).Range("C1").Value
sValue1 = Sheets(1).Range("A2").Value
sValue2 = Sheets(1).Range("B2").Value
sValue3 = Sheets(1).Range("C2").Value
I want to make a dynamic query like this:
StrQuery = "SELECT * FROM dbo.Table1 WHERE ('" & sColumn1 & "') LIKE ('" & sValue1 & "') AND ('" & sColumn2 & "') LIKE ('" & sValue2 & "') AND ('" & sColumn3 & "') LIKE ('" & sValue3 & "')"
This code does not generate any errors but IT DOES NOT pull any records either. I have confirmed and all the variables are being assigned the right values.
The query above works fine if I replace the Column variables for the actual column names in the SQL Table. Like this:
StrQuery = "SELECT * FROM dbo.Table1 WHERE Column1 LIKE ('" & sValue & "') AND Column2 LIKE ('" & sValue2 & "') AND Column3 LIKE ('" & sValue3 & "')"
With this string I get results without any problem but the columns will be dynamic. Users will choose from a variety of 15 columns.
Why is it that when I use the Variable it does not work even though I know the value of the variables matches exactly the names of the Columns in the SQL Table?
Am I using the wrong format in the string so that it reads the actual value stored within the variables?
Warnings above about using parameterized queries still apply but this is how you would get this to work:
StrQuery = "SELECT * FROM dbo.Table1 WHERE " & _
sColumn1 & " LIKE ('%" & sValue & "%')" & _
" AND " & sColumn2 & " LIKE ('%" & sValue2 & "%')" & _
" AND " & sColumn3 & " LIKE ('%" & sValue3 & "%')"
The answer by #TimWilliams should address the problem of not getting any result, provided the input is valid. However, as stated in the comments, the code is a bit brittle because entering malformed or otherwise inappropriate values into the fields of the sheet might produce interesting results. So, I would like to suggest a somewhat more robust approach than simply executing the SQL string.
If you are using ADO to talk to the SQL Server, you can call stored procedures on it as explained in this SO answer. Furthermore, provided you are at least on SQL Server 2008, there is the stored procedure sp_executesql. This stored procedure allows you to execute a SQL string containing parameters. The first parameter is the SQL string, the second a string containing the parameter list and the following parameters are the actual parameters for the query. This allows you to pass in the strings representing the LIKE pattern as actual string parameters. So, no matter what the values are, they cannot break the query itself.
Regarding the column names, you should at least escape them with square brackets. That is not waterproof, but it already goes a long way regarding accidentally malformed values.
The result would be something like
sqlString = "SELECT * FROM dbo.Table1 " & _
"WHERE [" & sColumn1 & "] LIKE #value1 " & _
" AND [" & sColumn2 & "] LIKE #value2 " & _
" AND [" & sColumn3 & "] LIKE #value3 "
parameterDeclarationString = "#value1 AS NVARCHAR(1000)," & _
"#value2 AS NVARCHAR(1000)," & _
"#value3 AS NVARCHAR(1000)"
Note that the max length of the parameters is just an arbitrary guess for a sensible upper limit.
I am trying to update access table using simple VBA code, however it finished with an error. I have tried various ways to solve it but without success.
Could you please help? The code is as follow:
strSQL = "UPDATE Projects " & _
"SET Projects.id_status = '" & Me.T_project_s.Value & "' " & _
"WHERE Projects.id_project = '" & Me.curr_open.Value & "';"
I have also tried:
strSQL = "UPDATE Projects " & _
"SET Projects.id_status = [" & Me.T_project_s.Value & "] " & _
"WHERE Projects.id_project = [" & Me.curr_open.Value & "];"
or
strSQL = "UPDATE [Projects] " & _
"SET [Projects].[id_status] = '" & Me.T_project_s.Value & "' " & _
"WHERE [Projects].[id_project] = '" & Me.curr_open.Value & "';"
But it asks for a data which is available in those fields.
Your suggestion helped. I started with only a text then I have changed particular variables I wanted to be read. So in the Where statement there is no need to have beside "" also '' :).
strSQL = "UPDATE [Projects] " & _
"SET [Projects].[id_status] = '" & Me.T_project_s.Value & "' " & _
"WHERE [Projects].[id_project] = " & Me.curr_open.Value & ";"
Thanks.
Once again, here is an example where parameterization (an industry best practice in SQL programming) helps beyond avoiding SQL injection. With querydef parameters you:
avoid the need of quote enclosure;
avoid string interpolation of variables;
abstract data (i.e., VBA variables) from code (i.e., SQL statement) for cleaner scripts;
(plus as OP found out with mixed types) explicitly define the data types of values to be binded;
execute the query via DAO for smoother user interface than DoCmd.RunSQL that raises warnings to users.
Temp Query
Dim qdef As QueryDef
' PREPARED STATEMENT, DEFINING PLACEHOLDERS (NO DATA)
strSQL = "PARAMETERS [project_s_param] Text(255), [curr_open_param] Long;" & _
" UPDATE [Projects]" & _
" SET [Projects].[id_status] = [project_s_param]" & _
" WHERE [Projects].[id_project] = [curr_open_param];"
' CREATE UNNAMED TEMP QUERYDEF, ASSIGNING PREPARED STATEMENT
Set qdef = CurrentDb.CreateQueryDef("", strSQL)
' BIND VBA VALUES TO PARAMETER PLACEHOLDERS
qdef![project_s_param] = Me.T_project_s.Value
qdef![curr_open_param] = Me.curr_open.Value
' EXECUTE ACTION
qdef.Execute dbFailOnError
Set qdef = Nothing
Saved Query
Even better, save entire prepared statement as a stored Access query and avoid any SQL in VBA.
SQL (save as any regular query object whose name is referenced in VBA)
PARAMETERS [project_s_param] Text(255), [curr_open_param] Long;
UPDATE [Projects]
SET [Projects].[id_status] = [project_s_param]
WHERE [Projects].[id_project] = [curr_open_param]
VBA
Dim qdef As QueryDef
' REFERENCE EXISTING QUERYDEF, ASSIGNING PREPARED STATEMENT
Set qdef = CurrentDb.QueryDefs("mySavedQuery")
' BIND VBA VALUES TO PARAMETER PLACEHOLDERS
qdef![project_s_param] = Me.T_project_s.Value
qdef![curr_open_param] = Me.curr_open.Value
' EXECUTE ACTION
qdef.Execute dbFailOnError
Set qdef = Nothing
I am trying to do a simple insert or update into SQL Server as NULL, not blank. I have seen many references online to just set Field = NULL without quotes but it is still coming up as empty, not NULL. Incredibly frustrating.
This is in classic asp.
If Request.Form("Field") = "" or IsNull(Request.Form("Field")) then
Field = NULL
Else
Field = Request.Form("Field")
End If
sSql="UPDATE [table] SET timestamp = {fn NOW()}," &_
"Field = '" & Field & "'," &_
"WHERE [System] = '" & System & "' and Active = '1'"
If I do this, it proves that it is checking because it puts in a 1.
If Request.Form("Field") = "" or IsNull(Request.Form("Field")) then
Field = 1
Else
Field = Request.Form("Field")
End If
sSql="UPDATE [table] SET timestamp = {fn NOW()}," &_
"Field = '" & Field & "'," &_
"WHERE [System] = '" & System & "' and Active = '1'"
I tried this but get an error 500:
sSql="UPDATE [Table] SET timestamp = {fn NOW()}, Field = "
If IsNull(Field) Then
sSQL = sSQL & "NULL"
Else
sSQL = sSQL & "'" & Field & "'" &_
End If
"NTLogon = '" & UCase(NTLogon) & "'" &_
"WHERE [System] = '" & System & "' and Active = '1'"
When I try this in place of my original code:
Field Assignment:
Field = "NULL" and Field = "'" & Request.Form("Field") & "'"
sSQL:
"Field = " & Field & "," &_
I get "An error occurred on the server when processing the URL."
So yeah, insert rant here about using parameterized queries, blah blah blah... now that's out of everyone's system, could we maybe look at the actual question?
The problem is this:
"Field = '" & Field & "'"
Those ampersands are converting your lovingly-populated vbScript NULL value right back into a string. If you don't want that to happen, you need to explicitly handle the IsNull case.
sSQL = "UPDATE [table] SET timestamp = {fn NOW()}, Field = "
If IsNull(Field) Then
sSQL = sSQL & "NULL"
Else
sSQL = sSQL & "'" & Field & "'"
End If
sSQL = sSQL & " WHERE [System] = '" & System & "' AND Active = '1'"
Note that even if you do this via a parameterized query, you'll need to make sure you're not appending your vbScript NULL value onto a string, because "" & NULL = "".
#pinchetpooche Hello there. I had the same issue and tried the given answer, and also received a 500 error page. I found that #Martha forgot to include the necessary SQL field that is being updated (i.e., "Field"). So I put together some test code, using her solution (i.e., using string concatenation and conditional logic), and executed against an actual database, and this solution works perfectly:
sSQLNullTest = "UPDATE CustomersToCCData SET "
sSQLNullTest = sSQLNullTest & "CustomerID = " & iCustomerID & ", "
If IsNull(x_license_number_state) Or x_license_number_state = "" Then
sSQLNullTest = sSQLNullTest & "CCLicenseState = NULL"
Else
sSQLNullTest = sSQLNullTest & "CCLicenseState = '" & x_license_number_state & "' "
End If
sSQLNullTest = sSQLNullTest & " WHERE CCID = '" & iCCInfoCCID & "'
i have a problem or lets say an error i get
i'm having that "Run Time-error '13' type mismatch" error when running this code
DoCmd.OpenReport "hamw_m3amala_naw_w_mawad", acViewReport, , "Jori_Mawad = '" & Combo14 & "' " And "ID =" & Combo4
note that Jori_Mawad is String and ID is Number
and that this two condition without the (And) do not have any problem and works fine :
DoCmd.OpenReport "hamw_m3amala_naw_w_mawad", acViewReport, , "Jori_Mawad = '" & Combo14 & "'"
DoCmd.OpenReport "hamw_m3amala_naw_w_mawad", acViewReport, , "ID = " & Combo4
Your
And
should be within the string that you are using as a where clause, but you are instead And-ing the first part of your clause with the second.
try
"Jori_Mawad = '" & Combo14 & "' And ID =" & Combo4
Working on a script in Microsoft VBA to take a massive flat database and split it between about 20 different tables. The script consists mainly of opening a table, checking every row in the flat database to make sure it's not a duplicate, then adding the necessary fields. Repeat for every table.
The first time I ran it everything was going well until I tried to process the name O'Malley. I think it's obvious what went wrong. A quick search on Google turned up this related StackOverflow post. I took their advice and added Replace(str, "'", "''") to every field before inputting it into the new tables. Now I've run into a new problem and Google is less helpful.
Replace(null, "'", "''") causes a run-time error, and the flat database is just riddled with null values. I can add an extra line above every Replace() call to check IsNull() and if so put null into the database instead of Replace(str, "'", "''"), although I would prefer a solution that can fit into a single line if possible. Is there any more elegant way to solve this dilemma, or will I need 216 If statements in my code?
EDIT -
Another reason that I'm searching for a more elegant solution is my duplicate checking code. At the moment I have something like the following:
'Check for duplicates
'Assume student is duplicate if it shares:
' (StudentName and School) or SSN
Set rstDuplicate = CurrentDb.OpenRecordset("select * from Student where (StudentName = '" & Replace(rstFrom("Student").Value, "'", "''") & "' AND School = '" & Replace(rstFrom("School").Value, "'", "''") & "') OR SSN = '" & Replace(rstFrom("Social").Value, "'", "''") & "'")
If rstDuplicate.RecordCount = 0 Then
'Duplicate was not found
rstTo.AddNew
' Add fields to the new table
rstTo.Update
End If
Since the Replace() calls are inline with the duplicate checking, if I were to instead use If statements to check for null then I would have to either save the result to a string or update to flat database. A function that returns Replace(str, "'", "''") OR null without the need for extra variables would be ideal.
If you want to keep everything inline, you can use an immediate If function (IIf):
IIf(IsNull(rstFrom("Student").Value), " Is Null", "= " & Replace(rstFrom("Student").Value)
That will be a nightmare to read and maintain, though. You are better off writing your own function to handle the change in comparison operator as well as the apostrophe escaping:
Function CompFld(Val As Variant) As String
If IsNull(Val) Then
CompFld = " Is Null "
Else
CompFld = "= '" & Replace(Val, "'", "''") & "' "
End If
End Function
Use it as so:
Dim SQL As String
SQL = "SELECT * FROM Student " & _
"WHERE (StudentName " & CompFld(rstFrom("Student").Value) & " AND " & _
" School " & CompFld(rstFrom("School").Value) & ") " & _
" OR (SSN " & CompFld(rstFrom("Social").Value) & ") "
Set rstDuplicate = CurrentDb.OpenRecordset(SQL)
If rstDuplicate.RecordCount = 0 Then
'Duplicate was not found
rstTo.AddNew
' Add fields to the new table
rstTo.Update
End If
A terse, yet ugly little gem handed down to me from ages ago:
Replace(str & "", "'", "''")
Appending an empty string to a null value returns an empty string in VBA, and won't modify a non-empty string.
Access' database engine will accept either single or double quotes as delimiters for string values in queries. So instead of ...
SELECT * FROM Student WHERE StudentName = 'O''Malley'
... you can do this ...
SELECT * FROM Student WHERE StudentName = "O'Malley"
That would allow you to handle inputs which contain apostrophes. OTOH, if your string inputs also contain double quotes, this will break.
I suspect you may have more going on than just the apostrophe issue, but I don't understand your big picture. You seem to be opening a third DAO recordset for each record in rstFrom, to check whether a match exists in the Student table. I would use DCount() instead.
Dim strCriteria As String
strCriteria = "StudentName = ""O'Malley"" AND School = ""foo"""
If DCount("*", "Student", strCriteria) = 0 Then
'no match found --> add it '
End If