views:

278

answers:

2

I had a working FREETEXTTABLE query that searched for a @searchString. I now need to UNION that with another simple query that tries to parse the @searchString into an INT, and if it succeeds, filtering the table by looking for the row with PK equal to the parse @searchString.

Previously, I could easily JOIN the FREETEXTTABLE result to the table it was searching, order by the Rank, but only SELECT the columns of the original table that was searched.

Now that I am combining the unique results between the text search query and the query looking for the row with the search string as the key, I no longer have access to the Rank from the text search query.

How can I maintain the ordering by rank of the full text search, but place the query result looking for the row with the primary key (if it has a result) BEFORE the full text search results?

A: 

Have you tried just adding a constant to your union that puts your exact match of the PK on the top of the list? I don't remember off the top of my head what the freetext RANK column returns (0 thru 1000 i think), but something like this would work assuming that you just make your constant higher than the top of the rank.

DECLARE @id int

IF ISNUMERIC(@myStringId) = 1
    SET @id = CAST(@myStringId AS int)
ELSE
    SET @id = 0

WITH MyFreetextCte as (SELECT   [Rank], 
                                [Key]
                       FROM     FREETEXTTABLE(...)
                       UNION
                       SELECT   1001, 
                                (SELECT MyBaseTable.PK FROM MyBaseTable WHERE PK = @id))
SELECT    *
FROM      MyFreetextCte JOIN MyBaseTable ON MyFreetextCte.[Key] = MyBaseTable.PK
ORDER BY  MyFreetextCte.Rank DESC
Scott Ivey
I can see the validity of your answer-- pulling the join away from the FREETEXTTABLE call and using it *after* the UNION. Unfortunately, I can't seem to get it to parse the SQL. It is giving me issues with usage of 'Rank' and 'Key'.Also, if @searchString is not a valid integer, will CAST throw an exception? I originally had a TRY CATCH block to set a value based on whether the a convert call was successful. If cast fails gracefully then I can just skip that.
Brandon
you could wrap that 2nd part of the union with a case statement - i'll update the example to reflect that. As for not parsing the query - i'm not sure what would cause your issues there...
Scott Ivey
Scott Ivey
Closer... I modified your SQL so that [Rank] is now RANK (only all caps worked for some reason), and also declared a variable and set as the casted int value in a try/catch block (since isnumeric is true even with existence of decimal, +, -, etc. which are not valid for an integer).Now it is parsing the SQL without errors. However it doesn't return the row that corresponds to the searchString being the primary key value.
Brandon
Upon further testing, it seems that the searchString being casted into an int works correctly, but as soon as I select it into MyFreetextCte as the KEY value, the value is changed from something like 0 or 50 or whatever, into a value like 478400592.Does a number being used as a KEY (if the key is an integer identity column) fundamentally change the way it is represented? I haven't seen anything like this before.
Brandon
I don't believe it does. In my database KEY returns an int. maybe double-check how you're casting the variable??
Scott Ivey
My database key returns an int, also. The issue is occurring before it is actually joined by the int.When this is executed:DECLARE @catalogBookID intSET @catalogBookID = 0;BEGIN TRY SET @catalogBookID = CAST(@searchPhrase AS int)END TRYBEGIN CATCH END CATCH;@catalogBookID is equal to the casted value (which is correct)SELECT RANK, [KEY] FROM FREETEXTTABLE(tbl_CatalogBooks, *, @searchPhrase)UNIONSELECT 1001, @catalogBookIDThat returns all the correct values from the FREETEXTTABLE part of the union. The other part returned (1001, 507367504), although the second number changes.
Brandon
I've posted an answer that has updated SQL-- I fixed the problem I was having. If you update your answer I will mark it as correct.Thanks for the help!
Brandon
A: 

WIth a ton of help from Scott, this is what I have that finally works:

CREATE PROCEDURE dbo.testProcedure
(
    @searchPhrase nvarchar(500)
)

AS

DECLARE @id int
SET @id = 0;
BEGIN TRY
 SET @id = CAST(@id AS int)
END TRY
BEGIN CATCH 
END CATCH;
-- at this point, @id will be the primary key if it is only digits
-- otherwise it will default to zero (which is out of range of my identity PK)

WITH ftsTable AS (
 SELECT RANK, [KEY] FROM FREETEXTTABLE(sourceTable, *, @searchPhrase)
 UNION
 SELECT 1001, (SELECT sourceTableID FROM sourceTable WHERE sourceTableID = @id)
) 

SELECT sourceTable.*
FROM ftsTable JOIN sourceTable ON ftsTable.[KEY] = sourceTable.sourceTableID
ORDER BY ftsTable.RANK DESC
Brandon