SQL Server лучший метод для сопоставления словосочетаний и порядка соответствия - PullRequest
7 голосов
/ 27 июня 2011

Каков наилучший способ ранжировать столбец sql varchar по количеству (количеству) / соответствию слов в параметре с четырьмя различными уникальными критериями.Вероятно, это не тривиальный вопрос, но мне нужно упорядочить строки на основе «наилучшего соответствия», используя мои критерии.

column: description varchar (100) Параметр: @MyParameter varchar (100)

Вывод с этим предпочтением заказа:

  • Точное совпадение (совпадение всей строки) - всегда первое
  • Начинается с (в зависимости от длины совпадения параметра)
  • Количество слов ранжируется с непрерывными словами, ранжирующимися выше для того же количества совпадений слов
  • Слова совпадают где угодно (не смежно)

Слова могут НЕ совпадать точно, так как частичносовпадения слова допустимы и, скорее всего, значение арендодателя должно применяться к частичным словам для ранжирования, но не критично (банк будет соответствовать каждому в: например, банк, гончар, прихватка, депо, депо).Начинается с совпадений с другими словами, ранжирование должно быть выше, чем у тех, у которых нет последующих совпадений, но это не является убийцей / супер важным.

Я хотел бы иметь метод ранжирования, где столбец «начинается» со значенияв параметре.Скажем, у меня есть следующая строка:

'This is my value string as a test template to rank on.'

Я хотел бы иметь, в первом случае, ранг столбца / строки, где существует наибольшее количество слов.

И второе место для ранжирования на основе вхождения (наилучшего совпадения) в начале как:

'This is my string as a test template to rank on.' - first
'This is my string as a test template to rank on even though not exact.'-second
'This is my string as a test template to rank' - third
'This is my string as a test template to' - next
'This is my string as a test template' - next etc.

Во-вторых: (возможно, второй набор / группа данных после первого (начинается с) -это желательно

Я хочу ранжировать (сортировать) строки по количеству слов в @MyParameter, которые встречаются в @MyParameter, с рангом, в котором смежные слова ранжируются выше, чем то же количество отдельно.

Таким образом, для приведенной выше строки 'is my string as shown' будет иметь более высокий ранг, чем 'is not my other string as' из-за "лучшего соответствия" смежной строки (слов вместе) с одинаковым количеством слов. Строки с более высоким соответствием (количество слов)это произойдет) будет ранжироваться по убыванию наилучшего совпадения в первую очередь.

Если возможно, я бы хотел сделать это в одном запросе.

В результате строка не должна встречаться дважды.

Из соображений производительности в таблице будет отображаться не более 10 000 строк.

Значения в таблице достаточно статичны, с небольшими изменениями, но не полностью.

Я не могу сизменить структуру в это время, но учту это позже (как таблица слов / фраз)

Чтобы сделать это немного сложнее, список слов находится в двух таблицах - но я мог бы создать представление для этого, норезультаты одной таблицы (меньший список) должны появляться до второй, более крупные результаты набора данных при одинаковом совпадении - будут дубликаты из этих таблиц, а также внутри таблицы, и мне нужны только отдельные значения.Выбрать DISTINCT непросто, так как я хочу вернуть один столбец (sourceTable), который вполне может выделить строки и в этом случае выбрать только из первой (меньшей) таблицы, но все остальные столбцы DISTINCT желательны (не считайте, чтостолбец в «отдельной» оценке.

Psuedo Столбцы в таблице:

procedureCode   VARCHAR(50),
description VARCHAR(100), -- this is the sort/evaluation column
category    VARCHAR(50),
relvu       VARCHAR(50),
charge  VARCHAR(15),
active  bit
sourceTable   VARCHAR(50) - just shows which table it comes from of the two

НЕТ уникального индекса, как столбец идентификатора

Соответствует НЕ в третьей таблице, чтобы бытьисключено SELECT * FROM (select * from tableone where procedureCode not in (select procedureCode from tablethree)) UNION ALL (select * from tabletwo where procedureCode not in (select procedureCode from tablethree))

РЕДАКТИРОВАТЬ: в попытке решить эту проблему, я создал параметр таблицы значения следующим образом:

0       Gastric Intubation & Aspiration/Lavage, Treatmen
1       Gastric%Intubation%Aspiration%Lavage%Treatmen
2       Gastric%Intubation%Aspiration%Lavage
3       Gastric%Intubation%Aspiration
4       Gastric%Intubation
5       Gastric
6       Intubation%Aspiration%Lavage%Treatmen
7       Intubation%Aspiration%Lavage
8       Intubation%Aspiration
9       Intubation
10      Aspiration%Lavage%Treatmen
11      Aspiration%Lavage
12      Aspiration
13      Lavage%Treatmen
14      Lavage
15      Treatmen

, где фактическая фраза находится в строке 0

Вот моя текущая попытка:

CREATE PROCEDURE [GetProcedureByDescription]
(   
        @IncludeMaster  BIT,
        @ProcedureSearchPhrases CPTFavorite READONLY

)
AS

    DECLARE @myIncludeMaster    BIT;

    SET @myIncludeMaster = @IncludeMaster;

    CREATE TABLE #DistinctMatchingCpts
    (
    procedureCode   VARCHAR(50),
    description     VARCHAR(100),
    category        VARCHAR(50),
    rvu     VARCHAR(50),
    charge      VARCHAR(15),
    active      VARCHAR(15),
    sourceTable   VARCHAR(50),
    sequenceSet VARCHAR(2)
    )

    IF @myIncludeMaster = 0
        BEGIN -- Excluding master from search   
          INSERT INTO #DistinctMatchingCpts (sourceTable, procedureCode, description    ,   category  ,charge, active, rvu, sequenceSet
) 
      SELECT DISTINCT sourceTable, procedureCode, description, category ,charge, active, rvu, sequenceSet
          FROM (
                  SELECT TOP 1
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''01'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] = PP.[LEVEL]
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)
                  ORDER BY PP.CODE

          UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM([CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable, 
                      ''02'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] LIKE PP.[LEVEL] + ''%''
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

          UNION ALL

            SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''03'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] LIKE ''%'' + PP.[LEVEL] + ''%''
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

            ) AS CPTS
            ORDER BY 
                 procedureCode, sourceTable, [description]
        END -- Excluded master from search
    ELSE
        BEGIN -- Including master in search, but present favorites before master for each code
            -- Get matching procedures, ordered by code, source (favorites first), and description.
            -- There probably will be procedures with duplicated code+description, so we will filter
            -- duplicates shortly.
      INSERT INTO #DistinctMatchingCpts (sourceTable, procedureCode, description    ,   category  ,charge, active, rvu, sequenceSet) 
      SELECT DISTINCT sourceTable, procedureCode, description, category ,charge, active, rvu, sequenceSet
          FROM (
                  SELECT TOP 1
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''00'' AS sequenceSet
                FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] = PP.[LEVEL]
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)
                  ORDER BY PP.CODE

                  UNION ALL

                  SELECT TOP 1
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[CATEGORY])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      COALESCE(CASE [ACTIVE] WHEN 1 THEN ''True'' WHEN 0 THEN ''False'' WHEN '''' THEN ''False'' ELSE ''False'' END,''True'') AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''2MasterCPT'' AS sourceTable,
                      ''00'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [MASTERCPT] AS CPT
                      ON CPT.[LEVEL] = PP.[LEVEL]
                  WHERE 
                      CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)
                  ORDER BY PP.CODE

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''01'' AS sequenceSet
                FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] = PP.[LEVEL]
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[CATEGORY])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      COALESCE(CASE [ACTIVE] WHEN 1 THEN ''True'' WHEN 0 THEN ''False'' WHEN '''' THEN ''False'' ELSE ''False'' END,''True'') AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''2MasterCPT'' AS sourceTable,
                      ''01'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [MASTERCPT] AS CPT
                      ON CPT.[LEVEL] = PP.[LEVEL]
                  WHERE 
                      CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

                  UNION ALL

                  SELECT TOP 1
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''02'' AS sequenceSet
                FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] LIKE PP.[LEVEL] + ''%''
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)
                  ORDER BY PP.CODE

                  UNION ALL

                  SELECT TOP 1
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[CATEGORY])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      COALESCE(CASE [ACTIVE] WHEN 1 THEN ''True'' WHEN 0 THEN ''False'' WHEN '''' THEN ''False'' ELSE ''False'' END,''True'') AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''2MasterCPT'' AS sourceTable,
                      ''02'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [MASTERCPT] AS CPT
                      ON CPT.[LEVEL] LIKE PP.[LEVEL] + ''%''
                  WHERE 
                      CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)
                  ORDER BY PP.CODE

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''03'' AS sequenceSet
                FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] LIKE PP.[LEVEL] + ''%''
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[CATEGORY])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      COALESCE(CASE [ACTIVE] WHEN 1 THEN ''True'' WHEN 0 THEN ''False'' WHEN '''' THEN ''False'' ELSE ''False'' END,''True'') AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''2MasterCPT'' AS sourceTable,
                      ''03'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [MASTERCPT] AS CPT
                      ON CPT.[LEVEL] LIKE PP.[LEVEL] + ''%''
                  WHERE 
                      CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[COMBO])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      ''True'' AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''0CPTMore'' AS sourceTable,
                      ''04'' AS sequenceSet
                FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [CPTMORE] AS CPT
                      ON CPT.[LEVEL] LIKE ''%'' + PP.[LEVEL] + ''%''
                  WHERE 
                      (CPT.[COMBO] IS NULL OR CPT.[COMBO] NOT IN (''Editor'',''MOD'',''CATEGORY'',''Types'',''Bundles''))
                      AND CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

                  UNION ALL

                  SELECT 
                      LTRIM(RTRIM(CPT.[CODE])) AS procedureCode, 
                      LTRIM(RTRIM(CPT.[LEVEL])) AS description, 
                      LTRIM(RTRIM(CPT.[CATEGORY])) AS category,
                      LTRIM(RTRIM(CPT.[CHARGE])) AS charge,
                      COALESCE(CASE [ACTIVE] WHEN 1 THEN ''True'' WHEN 0 THEN ''False'' WHEN '''' THEN ''False'' ELSE ''False'' END,''True'') AS active,
                      LTRIM(RTRIM([RVU])) AS rvu,
                      ''2MasterCPT'' AS sourceTable,
                      ''04'' AS sequenceSet
                  FROM 
                    @ProcedureSearchPhrases PP
                    INNER JOIN  [MASTERCPT] AS CPT
                      ON CPT.[LEVEL] LIKE ''%'' + PP.[LEVEL] + ''%''
                  WHERE 
                      CPT.[CODE] IS NOT NULL
                      AND CPT.[CODE] NOT IN (''0'', '''')
                    AND CPT.[CODE] NOT IN (SELECT CPTE.[CODE] FROM CPT AS CPTE WHERE CPTE.[CODE] IS NOT NULL)

             ) AS CPTS 

            ORDER BY 
                 sequenceSet, sourceTable, [description]

        END

        /* Final select - uses artificial ordering from the insertion ORDER BY */
        SELECT procedureCode, description,  category, rvu, charge, active FROM
        ( 
        SELECT TOP 500 *-- procedureCode, description,  category, rvu, charge, active
        FROM #DistinctMatchingCpts
        ORDER BY sequenceSet, sourceTable, description

        ) AS CPTROWS

        DROP TABLE #DistinctMatchingCpts

Однако это НЕ соответствует критериям наилучшего совпадения по количеству слов (как в значении строки 1 в образце), которое должно соответствовать наилучшему(большинство) найденных слов считаются из этой строки.

У меня есть полный контроль над формой / форматом параметра табличного значения, если это имеет значение.

Я возвращаю этот результатt на программу ac #, если это полезно.

Ответы [ 4 ]

5 голосов
/ 06 июля 2011

Чтобы решить эту проблему, вам нужно разделить строки. Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL

Для того, чтобы мой код, приведенный ниже, работал (а также моя функция разделения), вам необходимо выполнить настройку единого расписания:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

После настройки таблицы Numbers создайте эту функцию разделения:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(

    ----------------
    --SINGLE QUERY-- --this will not return empty rows
    ----------------
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''

);
GO 

Не стесняйтесь создавать свою собственную функцию разделения, но вам все еще нужна таблица Numbers, чтобы мое решениеработа.

Теперь вы можете легко разбить строку CSV на таблицу и присоединиться к ней:

select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,')

ВЫХОД:

ListValue
-----------------------
1
2
3
4
5
6777

(6 row(s) affected)

Теперь попробуйте это:

DECLARE @BaseTable table (RowID int primary key, RowValue varchar(100))
set nocount on
INSERT @BaseTable VALUES ( 1,'The cows came home empty handed')
INSERT @BaseTable VALUES ( 2,'This is my string as a test template to rank')                           -- third
INSERT @BaseTable VALUES ( 3,'pencil pen paperclip eraser')
INSERT @BaseTable VALUES ( 4,'wow')
INSERT @BaseTable VALUES ( 5,'no dice here')
INSERT @BaseTable VALUES ( 6,'This is my string as a test template to rank on even though not exact.') -- second
INSERT @BaseTable VALUES ( 7,'apple banana pear grape lemon orange kiwi strawberry peach watermellon')
INSERT @BaseTable VALUES ( 8,'This is my string as a test template')                                   -- 5th
INSERT @BaseTable VALUES ( 9,'rat cat bat mat sat fat hat pat ')
INSERT @BaseTable VALUES (10,'house home pool roll')
INSERT @BaseTable VALUES (11,'This is my string as a test template to')                                -- 4th
INSERT @BaseTable VALUES (12,'talk wisper yell scream sing hum')
INSERT @BaseTable VALUES (13,'This is my string as a test template to rank on.')                       -- first
INSERT @BaseTable VALUES (14,'aaa bbb ccc ddd eee fff ggg hhh')
INSERT @BaseTable VALUES (15,'three twice three once twice three')
set nocount off

DECLARE @SearchValue varchar(100)
SET @SearchValue='This is my value string as a test template to rank on.'

;WITH SplitBaseTable AS --expand each @BaseTable row into one row per word
(SELECT
     b.RowID, b.RowValue, s.ListValue
     FROM @BaseTable b
         CROSS APPLY  dbo.FN_ListToTable(' ',b.RowValue) AS s
)
, WordMatchCount AS --for each @BaseTable row that has has a word in common withe the search string, get the count of matching words
(SELECT
     s.RowID,COUNT(*) AS CountOfWordMatch
     FROM dbo.FN_ListToTable(' ',@SearchValue) v
         INNER JOIN SplitBaseTable             s ON v.ListValue=s.ListValue
     GROUP BY s.RowID
     HAVING COUNT(*)>0
)
, SearchLen AS --get one row for each possible length of the search string
(
SELECT
    n.Number,SUBSTRING(@SearchValue,1,n.Number) AS PartialSearchValue
    FROM Numbers n
    WHERE n.Number<=LEN(@SearchValue)
)
, MatchLen AS --for each @BaseTable row, get the max starting length that matches the search string
(
 SELECT
     b.RowID,MAX(l.Number) MatchStartLen
     FROM @BaseTable                 b
         LEFT OUTER JOIN SearchLen   l ON LEFT(b.RowValue,l.Number)=l.PartialSearchValue
     GROUP BY b.RowID
)
SELECT --return the final search results
    b.RowValue,w.CountOfWordMatch,m.MatchStartLen
    FROM @BaseTable                     b
        LEFT OUTER JOIN WordMatchCount  w ON b.RowID=w.RowID
        LEFT OUTER JOIN MatchLen        m ON b.RowID=m.RowID
    WHERE w.CountOfWordMatch>0
    ORDER BY w.CountOfWordMatch DESC,m.MatchStartLen DESC,LEN(b.RowValue) DESC,b.RowValue ASC

OUTPUT:

RowValue                                                                CountOfWordMatch MatchStartLen
----------------------------------------------------------------------- ---------------- -------------
This is my string as a test template to rank on.                        11               11
This is my string as a test template to rank on even though not exact.  10               11
This is my string as a test template to rank                            10               11
This is my string as a test template to                                 9                11
This is my string as a test template                                    8                11

(5 row(s) affected)

В этом случае совпадение начала строки слова немного отличается тем, что он смотрит на количество символов в начале соответствующей строки строки.

Как только вы это заработаете, вы можете попытаться оптимизировать его, создав несколько статических индексированных таблиц для SplitBaseTable.Возможно, используйте триггер на вашем @ BaseTable.

0 голосов
/ 13 июля 2011

Один ответ на все ваши проблемы: используйте sphynx http://sphinxsearch.com и не решайте это в SQL.

Sphynx имеет открытый исходный код, работает со всеми базами данных и всеми операционными системами.

Это то, что использует craigslist.

Это лучшая внешняя система полнотекстового поиска на момент публикации.Он упорядочит ваши результаты в соответствии с запрошенной вами релевантностью, и вам не понадобятся причудливые таблицы SQL или процедуры SQL.Попробуй.

0 голосов
/ 07 июля 2011

У меня был похожий вопрос некоторое время назад.Вопрос, на который я пытался ответить, состоял в том, сколько слов совпало между двумя разными столбцами, и ранжирование основывалось на наибольшем проценте совпадений слов.Это было далеко от меня, но я получил фантастический ответ от Мартина.

Посмотрите его ответ на мой вопрос здесь .

0 голосов
/ 27 июня 2011

Похоже, вы ищете подходящий алгоритм, который может быть трудно создать без использования хранимых процедур. Исходя из прошлого опыта, существуют алгоритмы редактирования расстояния (такие как Левенштейн), которые очень полезны для определения сходства. Они возвращают число, иногда количество различий между строками, по которым вы можете создать свое собственное весовое уравнение, чтобы получить оценку. Затем вы можете создать рейтинги или пороги для оценок, чтобы снизить количество ложных негативов / позитивов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...