SQL Server SQL Function for FullText search doesn't return results on first run

nzrxty8p  于 2023-08-02  发布在  其他
关注(0)|答案(1)|浏览(113)

I have a pretty extensive SQL Server query setup that performs the following functions. For each RDL report in our system (RDL is stored in a table as binary), I extract the CommandText from each dataset and store it in a table as VARCHAR(MAX). I have a separate table that holds client-created custom database objects (i.e. views, tables, stored procedures, and functions). The goal is for us to scan each report's CommandText for any references to the custom objects we've previously identified. I created a custom function that does the actual CONTAINS scan, and the CommandText is setup for FullText searching.

To be frank, everything works as I want. The issue is that the first time I run the script as a whole (Which includes building the report table to hold the report details, populating said table, creating the fulltext catalog and index, then updating the report table by querying it against the custom search function), the function does not return any results on objects that it should. If I then manually re-run the UPDATE statement that calls the function, it then returns the results as expected.

I do have all the major parts of this split up into batches (i.e. using GO) but it doesn't seem to make a difference. We really want this to be a single script if possible, so I appreciate any pointers or ideas to make sense of this. Scripts below for reference...

This is the part of my query that builds the full-text search index after my custom table that has all the report RDL details in it is populated:

CREATE UNIQUE CLUSTERED INDEX idx_ID ON dbo.tmpPremRptCmdTxt (ID)

    CREATE FULLTEXT CATALOG Prem_tmpPremRptCmdTxt_FTCat 
    CREATE FULLTEXT INDEX ON tmpPremRptCmdTxt
    (  
        DataSet_CommandText            
        Language 1033                 
    )  
        KEY INDEX idx_ID  
        ON Prem_tmpPremRptCmdTxt_FTCat  
        WITH CHANGE_TRACKING OFF

This is the part of the query that calls the function to do the scans and updates the report table if it finds any custom object references:

UPDATE tmpPremRptCmdTxt SET [CustomObjectsUsedInCommandText] = ISNULL(CustRptObjs.[CustomObjectsLocated], '')
FROM tmpPremRptCmdTxt 
LEFT JOIN (
    SELECT 
        ResultSet.ReportID, ResultSet.DatasetID
        , STRING_AGG('[' + CONVERT(VARCHAR(MAX), ResultSet.CustomObjects) + '] (' + ResultSet.ObjectType + ')', '; ') as [CustomObjectsLocated]
    FROM (
        SELECT 
            Rpt.ReportID, Rpt.DatasetID, Cob.ObjectType
            , dbo.[fnPremFTSearch_v2](MAX(Rpt.ID), Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName) as CustomObjects
        FROM tmpPremRptCmdTxt Rpt
        OUTER APPLY         
        (
            SELECT DISTINCT ObjectName, ObjectType 
            FROM tmpPremCustomObjects       
        ) Cob
        WHERE ISNULL(Rpt.DataSet_CommandText, '') <> ''     
        GROUP BY Rpt.ReportName, Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName,ObjectType
        HAVING dbo.[fnPremFTSearch_v2](MAX(Rpt.ID), Rpt.ReportID, Rpt.DatasetID, Cob.ObjectName) IS NOT NULL
    ) ResultSet
    GROUP BY ResultSet.ReportID, ResultSet.DatasetID
) CustRptObjs ON CustRptObjs.ReportID = tmpPremRptCmdTxt.ReportID
    AND CustRptObjs.DatasetID = tmpPremRptCmdTxt.DatasetID

This is the code of the function that I call to do the scan:

CREATE FUNCTION [dbo].[fnPremFTSearch_v2](@ID INT, @ReportID INT, @DatasetID INT, @ObjectName AS VARCHAR(256))
    RETURNS VARCHAR(256)
AS
BEGIN
    DECLARE @ReturnText VARCHAR(256) = ''
    , @SearchText VARCHAR(256) = CONCAT('"', @ObjectName, '"')

    SELECT @ReturnText = @ObjectName 
    FROM tmpPremRptCmdTxt
    WHERE ReportID = @ReportID 
    AND DatasetID = @DatasetID
    AND ID = @ID
    AND CONTAINS(DataSet_CommandText, @SearchText)
    AND DataSet_CommandText LIKE CONCAT('%',@ObjectName, '%') --Weeds out any near matches...i.e. "EmployeeDetail$" would return if CommandText contained "EmployeeDetail" but not "EmployeeDetail$"

    IF (@ReturnText = '')
        SET @ReturnText = NULL

    RETURN @ReturnText
END
GO
lf3rwulv

lf3rwulv1#

Might be a bit on the hacky side, but inspired by the comment from @AlwaysLearning about the asynchronous nature of populating the index, I was able to "fix" this by simply adding a wait command after creating the FTI. I just added the below code and now my end-result is returning the expected results.

WAITFOR DELAY '00:00:02';

相关问题