Organic wrote on Mon, 4 Feb 2008 09:03:01 -0800 (PST):
>> Organic wrote on Mon, 4 Feb 2008 07:40:39 -0800 (PST):
>>> On Feb 4, 9:34 am, "Daniel Crichton" <msn...@worldofspack.com>
>>> wrote:
>>>> Organic wrote on Mon, 4 Feb 2008 03:09:48 -0800 (PST):
>>>>> On Feb 4, 5:01 am, "Daniel Crichton" <msn...@worldofspack.com>
>>>>> wrote:
>>>>>> Organic wrote on Sun, 3 Feb 2008 13:26:02 -0800 (PST):
>>>>>>> I am creating a Full-Text Search application for a Visual Basic
>>>>>>> project and am having a problem with my sql query when I try to
>>>>>>> use filtering on a proximity search and try to order the
>>>>>>> results.
>>>>>>> I start with a simple CONTAINS FTS that is filtered and ordered.
>>>>>>> It works fine and allows filtering and ordering of results.
>>>>>>> The query works fine and I can filter it with the combobox, but
>>>>>>> of course the results are not ordered as I wish.
[quoted text clipped - 3 lines]
>>>>>>> Any thoughts on how to get the proximity search with a filter to
>>>>>>> also include the order clause?
>>>>>> Add a line of code printing out the SQL statement where you get
>>>>>> the syntax error - you should then be able to spot what is going
>>>>>> wrong.
>>>>>> --
>>>>>> Dan
>>>>> Hi Dan.
>>>>> I am not sure what you mean by adding a line of code printing out
[quoted text clipped - 3 lines]
>>>>> 'AND'". There are no details - only an "OK'" button to close the
>>>>> message box.
>>>> You can add a line to your application to show you what it's
>>>> sending to SQL
>>>> Server. After you build the SQL string, add a Debug.Print line (or
>>>> whatever your version of VB uses, I still use VB6)
>>>>> Here is the original code with the proximity (NEAR) version of the
>>>>> SQL statement that is giving me problems.
[quoted text clipped - 11 lines]
>>>>> Dim p1 As New SqlParameter("@p1", 1)
>>>>> command.Parameters.Add(p1)
>>>> This appears to allow @p1 to be empty. This might be your problem,
>>>> if
>>>> I'm reading it right (I use VB6 and ADO, not ADO.NET) and it
>>>> doesn't have a value then you might get
>>>> WHERE 1 = AND CONTAINS
>>>> which isn't valid syntax. What is the point of @p1? If it has a
>>>> value of 1 then the query will return results if the rest of the
[quoted text clipped - 4 lines]
>>>> value of the variable p1, and if it's not 1 then doesn't even run
>>>> the code as that would be more efficient.
>>>> --
>>>> Dan
>>> Dan, Thanks for your input.
>>> I am using Visual Studio 2008, Beta 2. I will be downloading the
[quoted text clipped - 11 lines]
>>> with it so decided to try the less elegant but usually more reliable
>>> appended query approach.
>> WHERE 1=1 just means "return all rows", because 1 will always equal
>> 1. It doesn't make any sense to have it in your query. And as I
>> pointed out, if p1 is empty then your SQL syntax is messed up.
>> For instance,
>> SELECT * FROM MyTable WHERE 1=1
>> will return all the rows in MyTable, and is the same as SELECT * FROM
>> MyTable
>> SELECT * FROM MyTable WHERE 1=1 AND Col1 = 'wibble'
>> is the same as SELECT * FROM MyTable WHERE Col1 = 'wibble'
>> SELECT * FROM MyTable WHERE 1=0
>> will return no rows, and you might as well not run the query at all
>> if you're expecting results.
>> Where did you get the idea that WHERE 1=1 does something special?
>> As to debugging, in VB6 I would put
>> Debug.Write adoRec.Source
>> where adoRec is an ADODB.Recordset object, to see what the string
>> being passed to SQL Server is before executing it. You should be able
>> to do something similar.
>>> I have tried Hillary's suggestion for using profiler but can't get
>>> Profiler to open the source table ("Only tables created by SQL
[quoted text clipped - 4 lines]
>>> in my datagrid, giving the user the choice of how to order the
>>> results rather than forcing it in my SQL.
>> I think it working when you remove the ORDER BY is just coincidental
>> - you should be concentrating on getting VB to print to the Immediate
>> window (or whatever the debug area is called now) to show what the
>> SQL string is before you pass it to SQL Server, until you do this
>> you'll have a hard time working out what's causing it.
>> --
>> Dan
> This is my procedure:
> I run the program and set the search parameters for the proximity
> search and select a filtering option from the combobox control. I
> click the search button to begin the search.
> I have set break points in the code so that I can monitor the values in
> the Locals window.
> As I step through the code, the initial value of myQuery cannot be
> determined. Here is the printout:
> "Chars In order to evaluate an indexed property, the property must be
> qualified and the arguments must be explicitly supplied by the user."
> As I continue to step through the code and get to the p2 parameter that
> is appended to the query, the value of myQuery reads:
> "Chars Argument not specified for parameter 'index' of 'Public
> Property Chars(index As Integer) As Char'."
> I don't know if this is referring to a data type problem with the p2
> appended query, or simply an inability to determine the value of the
> filter, or something else. Any thoughts on what this means?
No idea. I haven't used VB.NET yet.
However, I'm still confused by what "1 = @p1" will achieve. In the code
you've posted so far you've include some string building, and added 2
parameters - but where is the code that sets the value of the @p1 parameter?
Where is the code that passes the myQuery string into the SQLCommand object?
Your code example is incomplete, but given that you set the value of @p2
when you create the parameter, and you've not set the value of @p1 earlier
in the code, I think I see why it's not working and why you've got that "1 =
" in there.
I've seen the use of 1=1 at the start of WHERE in some dynamic SQL building
where the coder doesn't want to have to worry about whether the SQL already
has a WHERE clause or not, they just want to append "AND ..." each time, and
it doesn't matter if an earlier piece of the SQL is left out due to program
flow. It looks like that's what you're doing here, but you've made a
fundamental error - you missed out the second 1.
a = "SELECT * FROM MyTable WHERE 1=1"
b =" AND Col1 = 'blah'"
c = " AND Col2 = 'wibble'"
if you take a+b+c , you get
SELECT * FROM MyTable WHERE 1=1 AND Col1 = 'blah' AND Col2 = 'wibble'
which is valid SQL. If b= '', then the result is
SELECT * FROM MyTable WHERE 1=1 AND Col2 = 'wibble'
which is still valid.
However, if the code requires the 1 to be included in the first string
concatenation, and it's missing, things start to go horribly wrong.
a = "SELECT * FROM MyTable WHERE 1="
b ="1 AND Col1 = 'blah'"
c = " AND Col2 = 'wibble'"
a+b+c =
SELECT * FROM MyTable WHERE 1=1 Col1 = 'blah' AND Col2 = 'wibble'
which is valid
if b = '' however, then a+b+c becomes
SELECT * FROM MyTable WHERE 1= AND Col2 = 'wibble'
and you get the syntax you're seeing.
So, go back to your code, and find where you're setting the value of the @p1
parameter. Check the value - if it's empty, or doesn't start with 1, then
your query won't work.

Signature
Dan
Organic Man - 04 Feb 2008 18:14 GMT
> Organic wrote on Mon, 4 Feb 2008 09:03:01 -0800 (PST):
>
[quoted text clipped - 220 lines]
> --
> Dan
Dan:
Thanks again for your input.
Creating appended queries with WHERE 1 = @p1 is a technique I learned
from VB programmers in the MSDN Forum. It has always worked for me so
I have used it for complex searches like this. I have always assumed
that 1 = @p1 is a placeholder that simply opens the query to
additional parameters with values that can be defined at runtime.
As I reflect on your comments above (and the apparent limitations of
this approach), I am inclined to go to Plan B, which is a stored
procedure that accomplishes essentially the same thing and is probably
a bit faster and more secure. I have one bug with the SP that I need
to work out, and may bring it before this forum if I can't get it
solved on my own.
As you requested, here is the complete code for the proximity search
with multiple filters that derive from the specific appended query
parameters. It runs fine and allows all 6 filters to work quite
well. However it doesn't have the ORDER BY clause in the query:
Private Sub btnProximitySearch_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles btnProximitySearch.Click
Dim SearchTerm1
SearchTerm1 = txtProximitySearch1.Text
Dim SearchTerm2
SearchTerm2 = txtProximitySearch2.Text
Dim Connection As New SqlConnection(DataSource)
Dim command As New SqlCommand()
command.Connection = Connection
Dim myQuery As New System.Text.StringBuilder()
myQuery.Append("SELECT FullDocuments.FullDocNo,
FullDocuments.DocType, Details.YearGiven FROM FullDocuments INNER JOIN
Details ON FullDocuments.FullDocNo = Details.FullDocNo WHERE 1 = @p1
AND CONTAINS (SectionText, ' """ & SearchTerm1 & """ NEAR """ &
SearchTerm2 & """ ')")
Dim p1 As New SqlParameter("@p1", 1)
command.Parameters.Add(p1)
If cmbProximityDocType.SelectedIndex > 0 Then
myQuery.Append(" AND DocType = @p2")
Dim p2 As New SqlParameter("@p2", SqlDbType.VarChar, 10)
p2.Value = cmbProximityDocType.Text.ToString
command.Parameters.Add(p2)
End If
If Not txtProximityYear.Text.Length = 0 Then
myQuery.Append(" AND YearGiven = @p3")
Dim p3 As New SqlParameter("@p3", SqlDbType.SmallInt)
p3.Value = txtProximityYear.Text.ToString
command.Parameters.Add(p3)
End If
If cmbProximitySex.SelectedIndex > 0 Then
myQuery.Append(" AND Sex = @p4")
Dim p4 As New SqlParameter("@p4", SqlDbType.VarChar, 10)
p4.Value = cmbProximitySex.Text.ToString
command.Parameters.Add(p4)
End If
If cmbProximityCategory.SelectedIndex > 0 Then
myQuery.Append(" AND Category = @p5")
Dim p5 As New SqlParameter("@p5", SqlDbType.NVarChar, 10)
p5.Value = cmbProximityCategory.Text.ToString
command.Parameters.Add(p5)
End If
If cmbProximityAgeCat.SelectedIndex > 0 Then
myQuery.Append(" AND AgeCat = @p6")
Dim p6 As New SqlParameter("@p6", SqlDbType.VarChar, 10)
p6.Value = cmbProximityAgeCat.Text.ToString
command.Parameters.Add(p6)
End If
If Not txtProximityAgeNum.Text.Length = 0 Then
myQuery.Append(" AND AgeNum = @p7")
Dim p7 As New SqlParameter("@p7", SqlDbType.SmallInt)
p7.Value = txtProximityAgeNum.Text.ToString
command.Parameters.Add(p7)
End If
command.CommandText = myQuery.ToString
Dim da As New SqlDataAdapter(command)
Dim ds As New DataSet()
Try
Connection.Open()
Cursor = Cursors.WaitCursor()
da.Fill(ds)
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
Connection.Close()
Cursor = Cursors.Default
End Try
If ds.Tables.Count > 0 Then
datProximityResults.DataSource = ds.Tables(0)
Else
datProximityResults.DataSource = Nothing
End If
End Sub
Daniel Crichton - 05 Feb 2008 09:25 GMT
Organic wrote on Mon, 4 Feb 2008 10:14:29 -0800 (PST):
> Creating appended queries with WHERE 1 = @p1 is a technique I learned
> from VB programmers in the MSDN Forum. It has always worked for me so
> I have used it for complex searches like this. I have always assumed
> that 1 = @p1 is a placeholder that simply opens the query to additional
> parameters with values that can be defined at runtime.
As I stated before, it'll only work if @p1 has a value starting with 1. Go
back to other applications you've written that use this technique and look
at what they set @p1 to. I'm pretty sure you should be setting the p1
parameter to 1 in your code, but you seem to have missed that step. It's
also unnecessary, for the reasons I posted in my earlier replies. It's a
technique I've seen, albeit rarely, and I've been programming VB for 14
years writing commercial applications.
> As I reflect on your comments above (and the apparent limitations of
> this approach), I am inclined to go to Plan B, which is a stored
> procedure that accomplishes essentially the same thing and is probably
> a bit faster and more secure. I have one bug with the SP that I need
> to work out, and may bring it before this forum if I can't get it
> solved on my own.
An SP is a better idea if you can manage it. Try to steer away from dynamic
SQL if at all possible, but if you do use dynamic SQL you've at least taken
the right steps in using parameters rather than concatenating values inline.
> As you requested, here is the complete code for the proximity search
> with multiple filters that derive from the specific appended query
> parameters. It runs fine and allows all 6 filters to work quite well.
> However it doesn't have the ORDER BY clause in the query:
> Dim p1 As New SqlParameter("@p1", 1)
> command.Parameters.Add(p1)
This is the only place you reference p1, and it doesn't get given a value. I
cannot see how this could possibly work even without the ORDER BY. It looks
like you might have missed a couple of commas out of the SqlParameter line,
and that 1 should be in the value position, not in the datatype position
it's in now. If all this is supposed to do is set @p1 to 1, then you can
skip this step and just change @p1 to 1 in the initial string.
> command.CommandText = myQuery.ToString
Before this line, you should be able to print out the value of
myQuery.ToString. If it's got WHERE 1 = @p1 AND in it, and you still haven't
set the value of the parameter p1 then the syntax is invalid.
I've done a Google search for "WHERE 1 = @p1" to find other posts about this
technique, and the only result is this thread. Searching for "WHERE 1 = 1"
finds thousands of results - and for this reason I'm convinced you've made a
mistake here.

Signature
Dan
Organic Man - 05 Feb 2008 22:34 GMT
> Organic wrote on Mon, 4 Feb 2008 10:14:29 -0800 (PST):
>
[quoted text clipped - 50 lines]
> --
> Dan
Dan:
I don't have an answer to your questions/comments other than it seems
to work for most simple FTS queries.
But you have convinced me to abandon this approach and just use a
stored procedure.
Best wishes, Dave