SQL查询 - 递归细化

时间:2012-01-12 19:27:26

标签: sql-server tsql common-table-expression

我正在尝试将由字符分隔的字符串传递给存储过程,而我想要做的是对这些字执行SELECT,以便每个后续SELECT在其之前查询结果集。我一直在研究如何使用递归CTE实现这一点,但我无法找到一种正确的方法来设置锚点和终结符以使递归正常工作。我知道我可以在我的服务器端代码(C#)上执行此操作,但我很乐意不必重复调用DB,因为我知道可以在那里完成。下面是存储过程,减去任何拆分类型的操作以拆分字符串和我所做的任何黑客递归尝试(即它所做的只是返回一个关键字的结果集):

ALTER PROCEDURE searchTests

@searchQuery varchar(200)

AS

SELECT 
    TestID, [Test Name], [Specimen Type], Methodology, [Performing Lab]
FROM RolodexTestDB
WHERE
    (RolodexTestDB.inactive IS NULL OR NOT RolodexTestDB.inactive = 'Yes')
    AND (
        RolodexTestDB.[Test Name] Like '%' + @searchQuery + '%'
        or RolodexTestDB.Methodology Like '%' + @searchQuery + '%'
        or RolodexTestDB.[Synonyms] Like '%' + @searchQuery + '%'
        or RolodexTestDB.[Specimen Type] Like '%' + @searchQuery + '%'
        or RolodexTestDB.[Included Tests] Like '%' + @searchQuery + '%'
    )
)
ORDER BY [Test Name]

1 个答案:

答案 0 :(得分:0)

听起来像使用全文索引的理想场景,这样你可以使用CONTAINS()?

http://msdn.microsoft.com/en-us/library/ms187787.aspx

如果您无法访问全文索引,可以尝试将字符串拆分为表,然后加入该表,然后计算重复项(通过对主键进行分区。未经测试的示例:

CREATE FUNCTION [dbo].[fnc_Split]
    (
      @Data VARCHAR(2000) ,
      @Sep VARCHAR(5)
    )
RETURNS @Temp TABLE
    (
      Id INT IDENTITY(1, 1) ,
      Data NVARCHAR(100)
    )
AS 
    BEGIN
        DECLARE @Cnt INT
        SET @Cnt = 1
        WHILE ( CHARINDEX(@Sep, @Data) > 0 ) 
            BEGIN
                INSERT  INTO @Temp
                        ( data
                        )
                        SELECT  Data = LTRIM(RTRIM(SUBSTRING(@Data, 1, CHARINDEX(@Sep, @Data) - 1)))
                SET @Data = SUBSTRING(@Data, CHARINDEX(@Sep, @Data) + 1, LEN(@Data))
                SET @Cnt = @Cnt + 1
            END
        INSERT  INTO @Temp
                ( data )
                SELECT  Data = LTRIM(RTRIM(@Data))
        RETURN
    END

GO

DECLARE @SearchString VARCHAR(MAX)
SET @SearchString = 'blood HIV white'

--#### Build Pattern Table
DECLARE @PatternTable TABLE
    (
      ID INT NOT NULL ,
      PATTERN VARCHAR(50)
    )
INSERT  INTO @PatternTable
        ( ID ,
          PATTERN
        )
        SELECT  ID ,
                CASE WHEN ID = 1 THEN Data + '%'
                     ELSE '% ' + Data + '%'
                END AS Data
        FROM    fnc_Split(@SearchString, ' ');

--#### Fetch list of matching Primary keys (repeat CTEs for each column)
WITH    PrepSearch ( PrimaryKey, MatchedWords )
          AS ( SELECT   PrimaryKey ,
                        COUNT(PrimaryKey) OVER ( PARTITION BY PrimaryKey ) AS MatchedWords
               FROM     dbo.RolodexTestDB P ( NOLOCK )
                        INNER JOIN @PatternTable S ON P.Methodology LIKE S.PATTERN COLLATE DATABASE_DEFAULT
             ),
        SearchResults ( PRO_CODE )
          AS ( SELECT   PrimaryKey
               FROM     PrepSearch
               WHERE    MatchedWords = (SELECT COUNT(ID) FROM @PatternTable)
               GROUP BY PrimaryKey
             )
    SELECT  *
    FROM    SearchResults