Search code examples
sqlfull-text-searchcontainstable

how to write containstable searchcondition with and's and or's


Currently trying to write a select statement with a containstable and the search condition is giving me some grief.

The purpose is to search a table with 3 different parameter types and rank the output accordingly. (below is sample of my code)

  1. Key search condition (must-have and weighted at 1) || testvalue = Accountant
  2. Additional must-have (weighted .8) || testvalue = Manager
  3. Nice to have (weighted .5) || testvalue = Excel

SQL:

 SELECT KTBL.Rank as [Ranking], KeySkills
   FROM Applicants INNER JOIN 
      CONTAINSTABLE(Applicants, KeySkills, 
        '(ISABOUT("Accountant" weight(1))) & 
         (ISABOUT("Manager" weight(.8))) | 
         (ISABOUT("Excel") weight(.5)))
     AS KTBL
   ON Applicants.Id = KTBL.[KEY];

The above statement does not return anything and I'm doubting whether its possible to stack isabout terms in the above manner.

The returned results must have both accountant AND manager and would be nice to have Excel

Any suggestions to have I can achieve this?


Solution

  • I eventually came up with a solution to my own question that I'm happy with for the time being.

    I ended up with the stored procedure as seen below here (a bit long winded) which takes 3 parameters 1. Primary Search Key (must match) 2. Additional Must Have comma separated string (must match) 3. Additional Nice to have comma separated string

    CREATE PROCEDURE [dbo].[GetJobSeekers]
    (
    @KeywordSearch nvarchar(500),
    @MustHave nvarchar(500), --Comma separated skills
    @NiceToHave nvarchar(500) --Comma separated skills
    )
    AS
    BEGIN
    
    SET NOCOUNT ON;
    
    DECLARE @SQL nvarchar(4000)
    DECLARE @SELECT nvarchar(4000)
    DECLARE @SEARCH nvarchar(4000)
    DECLARE @SEARCH1 nvarchar(4000)
    DECLARE @SEARCH2 nvarchar(4000)
    DECLARE @WHERE nvarchar(4000)
    DECLARE @ORDERBY nvarchar(4000)
    
    /*Used for string split*/
    DECLARE @POS int
    DECLARE @NEXTPOS int
    
    /*Get Result for primary search key*/
    SET @SELECT =   'SELECT ktbl.rank AS [Ranking], jobseekers.*'
    SET @SEARCH =   'ISABOUT("'+@KeywordSearch+'" weight(1))'
    
    SET @WHERE  =   ' FROM jobseekers INNER JOIN
                    CONTAINSTABLE (jobseekers, *, ''' + @SEARCH + ''')
                    AS ktbl On jobseekers.Id = ktbl.[KEY]'
    
    SET @ORDERBY=   'ORDER BY [Ranking] DESC'
    
    /* Get Result set for all additional must have keywords and INNER JOIN With primary Search */
    IF @MustHave <> ''
    
    BEGIN
        DECLARE @MustHaveSplitString nvarchar(500)
    
        SET @POS = 1
        WHILE(@POS <= LEN(@MustHave))
        BEGIN
            SELECT @NEXTPOS = CHARINDEX(N',', @MustHave,  @POS)
            IF (@NEXTPOS = 0 OR @NEXTPOS IS NULL)
                  SELECT @NEXTPOS = LEN(@MustHave) + 1
            SELECT @MustHaveSplitString = RTRIM(LTRIM(SUBSTRING(@MustHave, @POS, @NEXTPOS - @POS)))
    
            SET @SELECT = @SELECT + ', ktbl'+@MustHaveSplitString+'.rank AS [Ranking'+@MustHaveSplitString+']'
            SET @ORDERBY = @ORDERBY + ', [Ranking'+@MustHaveSplitString+'] DESC'
            SET @SEARCH1 = 'ISABOUT("'+@MustHaveSplitString+'" weight(.8))'
            SET @WHERE = @WHERE + ' INNER JOIN CONTAINSTABLE (jobseekers, *, ''' + @SEARCH1 + ''')
                                    AS ktbl'+@MustHaveSplitString+' on Jobseekers.Id = ktbl'+@MustHaveSplitString+'.[KEY]'
            SELECT @POS = @NEXTPOS+1    
        END 
    END
    
    
    /*Get result set for all nice to have by stacking them in the isabout searchcondition and LEFT OUTER JOIN with Primary Search + Must have search if its there*/
    IF @NiceToHave <> ''
    BEGIN
        DECLARE @NiceToHaveSplitString nvarchar(500)        
        SET @SEARCH2 = 'ISABOUT('
    
        SET @POS = 1
        WHILE(@POS <= LEN(@NiceToHave))
        BEGIN
            SELECT @NEXTPOS = CHARINDEX(N',', @NiceToHave,  @POS)
            IF (@NEXTPOS = 0 OR @NEXTPOS IS NULL)
                  SELECT @NEXTPOS = LEN(@NiceToHave) + 1
            SELECT @NiceToHaveSplitString = RTRIM(LTRIM(SUBSTRING(@NiceToHave, @POS, @NEXTPOS - @POS)))
    
            SET @SEARCH2 = @SEARCH2 + '"'+@NiceToHaveSplitString+'" weight(.5),'            
    
            SELECT @POS = @NEXTPOS+1    
        END         
        /*Clean last , off the search2 string */
        SET @SEARCH2 = LEFT(@SEARCH2, LEN(@SEARCH2) -1)
        /*Close the isabout in search2 string*/
        SET @SEARCH2 = @SEARCH2 + ')'
    
    
        SET @SELECT = @SELECT + ', ktbl2.rank AS [Ranking2]'
        SET @ORDERBY = @ORDERBY + ', [Ranking2] DESC'
    
        SET @WHERE = @WHERE + ' LEFT JOIN CONTAINSTABLE (jobseekers, *, ''' + @SEARCH2 + ''')
                                AS ktbl2 on Jobseekers.Id =          ktbl2.[KEY]'
    END
    
    SET @SQL    =   @SELECT + @WHERE + @ORDERBY
    
    EXEC sp_executesql @SQL
    END
    

    The stored procedure is still not 100% complete as it needs to take additional logic into consideration but it will for the time being act as a shell for the end result. Also I have yet to test this against any substantial amount of data so I'm still unsure how well it will perform.

    Kind regards,