SQL Server - бесплатный текстовый поиск с пустым ключевым словом - PullRequest
5 голосов
/ 04 мая 2011

Ниже приведена упрощенная версия моего sql-запроса, в котором для полнотекстового поиска используется CONTAINSTABLE .

DECLARE @pSearchFor AS NVARCHAR(100);
SET @pSearchFor = 'SomeKeyword';

SELECT MS.[ModuleScreenID] AS ScreenID
    ,MS.[ModuleScreenCode] AS ScreenCode
    ,M.[Description] AS ModuleDescription
    ,M.[ModuleCode] AS ModuleCode        
    ,FT.[Rank] 
FROM ModuleScreen MS
    JOIN Module M ON MS.ModuleID = M.ModuleID
    JOIN CONTAINSTABLE(ModuleScreen, *, @pSearchFor) FT ON MS.ModuleScreenID = FT.[KEY]

Я хочу передать пустое или нулевое значение для параметра @pSearchFor, чтобы все записи возвращались при полнотекстовом поиске. Но я получаю «Null or empty полнотекстовый предикат» , когда я передаю пустое или нулевое значение. После поиска в Google я обнаружил, что CONTAINSTABLE не может принимать пустой параметр для ключевых слов. Я также видел этот вопрос в SO, но он мне не помог.

Можно ли сделать условное соединение с CONTAINSTABLE (только если для параметра @pSearchFor указано значение)? Я не уверен, как этого добиться. Был бы признателен за любые указатели.

Ответы [ 3 ]

3 голосов
/ 21 июня 2011
DECLARE @pSearchFor AS NVARCHAR(100);

SET @pSearchFor = 'SomeKeyword';
--if @pSearch comes as parameter then --
set @pSearch = ISNULL(@pSearch,'*')

SELECT MS.[ModuleScreenID] AS ScreenID
    ,MS.[ModuleScreenCode] AS ScreenCode
    ,M.[Description] AS ModuleDescription
    ,M.[ModuleCode] AS ModuleCode        
    ,FT.[Rank] 
FROM ModuleScreen MS
    JOIN Module M ON MS.ModuleID = M.ModuleID
    JOIN CONTAINSTABLE(ModuleScreen, *, @pSearchFor) FT ON MS.ModuleScreenID = FT.[KEY]
where @pSearchFor = '*' OR FT.[KEY] is not null

Я только что решил ту же проблему и подумал о том, чтобы помочь вам.

0 голосов
/ 23 декабря 2011

У меня была точно такая же проблема, и я решил ее, добавив / добавив фиктивное ключевое слово 'fts' в индексированный столбец поиска для всех записей.

if(nullif(@pSearchFor,'') is null)
begin
     set @pSearchFor= 'fts';                
end
0 голосов
/ 04 мая 2011

Что вы ожидаете получить при поиске пустого или нулевого значения? ожидаете ли вы, что запрос ничего не даст, или ожидаете, что он вернет что-то еще.

Если вы хотите, чтобы он ничего не возвращал, то лучше всего сделать что-то вроде этого:

DECLARE @pSearchFor AS NVARCHAR(100);
SET @pSearchFor = 'SomeKeyword';

IF @pSearchFor IS NOT NULL AND @pSearchFor <> '' 
BEGIN
    SELECT MS.[ModuleScreenID] AS ScreenID
        ,MS.[ModuleScreenCode] AS ScreenCode
        ,M.[Description] AS ModuleDescription
        ,M.[ModuleCode] AS ModuleCode        
        ,FT.[Rank] 
    FROM ModuleScreen MS
        JOIN Module M ON MS.ModuleID = M.ModuleID
        JOIN CONTAINSTABLE(ModuleScreen, *, @pSearchFor) FT ON MS.ModuleScreenID = FT.[KEY]
END
ELSE
BEGIN
    SELECT MS.[ModuleScreenID] AS ScreenID
        ,MS.[ModuleScreenCode] AS ScreenCode
        ,M.[Description] AS ModuleDescription
        ,M.[ModuleCode] AS ModuleCode        
        ,FT.[Rank] 
    FROM ModuleScreen MS
        JOIN Module M ON MS.ModuleID = M.ModuleID
END

edit: исправлена ​​ошибка, из-за которой теперь возвращаются все записи, когда указана пустая или пустая строка.

Если у вас более 2 запросов таблиц CONTAINS с разными строками поиска, я бы посоветовал вам сгенерировать запрос с использованием динамического SQL, поскольку его было бы намного проще поддерживать, чем цепочку из 2 ^ n почти одинаковых запросов

Редактировать: рассмотрев способ сделать это без использования нескольких копий, используя временную таблицу, подобную этой:

DECLARE @pSearchFor AS NVARCHAR(100);
SET @pSearchFor = 'SomeKeyword';

SELECT * INTO #temp FROM CONTAINSTABLE(ModuleScreen, *, @pSearchFor)

SELECT MS.[ModuleScreenID] AS ScreenID
    ,MS.[ModuleScreenCode] AS ScreenCode
    ,M.[Description] AS ModuleDescription
    ,M.[ModuleCode] AS ModuleCode        
    ,FT.[Rank] 
FROM Module M
    JOIN ModuleScreen MS ON MS.ModuleID = M.ModuleID AND (
        (1 = CASE WHEN ISNULL(@pSearchFor, '') = '' THEN 1 ELSE 0 END
        OR CONTAINS(MS.*, @pSearchFor)
    LEFT OUTER JOIN #temp FT ON MS.ModuleScreenID = FT.[Key]

Это должно дать вам то, что вы хотите, без необходимости дублировать вещи, однако вы можете захотеть еще больше ограничить результат, который подается в таблицу #temp, поскольку он будет медленным для больших таблиц.

...