SQL выберите, где поле содержит слова

Мне нужен выбор, который вернет такие результаты:

SELECT * FROM MyTable WHERE Column1 CONTAINS 'word1 word2 word3'

и мне нужны все результаты, т. е. это включает строки с "word2 word3 word1" или "word1 word3 word2" или любой другой комбинацией из трех.

все слова должны быть в результате.

14 ответов


довольно медленный, но рабочий метод для включения любой слова:

SELECT * FROM mytable
WHERE column1 LIKE '%word1%'
   OR column1 LIKE '%word2%'
   OR column1 LIKE '%word3%'

Если вам нужно все слова, чтобы присутствовать, используйте это:

SELECT * FROM mytable
WHERE column1 LIKE '%word1%'
  AND column1 LIKE '%word2%'
  AND column1 LIKE '%word3%'

Если вы хотите что-то быстрее, то вам нужно заглянуть в полнотекстовый поиск, и это очень специфично для каждого типа базы данных.


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

если ваш SQL диалект поддерживает CHARINDEX, гораздо проще использовать его вместо этого:

SELECT * FROM MyTable
WHERE CHARINDEX('word1', Column1) > 0
  AND CHARINDEX('word2', Column1) > 0
  AND CHARINDEX('word3', Column1) > 0

кроме того, имейте в виду, что это и метод в принятом ответе охватывают только соответствие подстроки, а не сопоставление слов. Так, например, строка 'word1word2word3' все равно совпадет.


функции

 CREATE FUNCTION [dbo].[fnSplit] ( @sep CHAR(1), @str VARCHAR(512) )
 RETURNS TABLE AS
 RETURN (
           WITH Pieces(pn, start, stop) AS (
           SELECT 1, 1, CHARINDEX(@sep, @str)
           UNION ALL
           SELECT pn + 1, stop + 1, CHARINDEX(@sep, @str, stop + 1)
           FROM Pieces
           WHERE stop > 0
      )

      SELECT
           pn AS Id,
           SUBSTRING(@str, start, CASE WHEN stop > 0 THEN stop - start ELSE 512 END) AS Data
      FROM
           Pieces
 )

запрос

 DECLARE @FilterTable TABLE (Data VARCHAR(512))

 INSERT INTO @FilterTable (Data)
 SELECT DISTINCT S.Data
 FROM fnSplit(' ', 'word1 word2 word3') S -- Contains words

 SELECT DISTINCT
      T.*
 FROM
      MyTable T
      INNER JOIN @FilterTable F1 ON T.Column1 LIKE '%' + F1.Data + '%'
      LEFT JOIN @FilterTable F2 ON T.Column1 NOT LIKE '%' + F2.Data + '%'
 WHERE
      F2.Data IS NULL

вместо SELECT * FROM MyTable WHERE Column1 CONTAINS 'word1 word2 word3', добавить и между этими словами, как:

SELECT * FROM MyTable WHERE Column1 CONTAINS 'word1 And word2 And word3'

Подробнее см. здесь https://msdn.microsoft.com/en-us/library/ms187787.aspx

обновление

для выбора фраз, используйте двойные кавычки, как:

SELECT * FROM MyTable WHERE Column1 CONTAINS '"Phrase one" And word2 And "Phrase Two"'

п.з. вы должны сначала включить полнотекстовый поиск по таблице перед использованием содержит ключевое слово. дополнительные сведения см. здесь https://docs.microsoft.com/en-us/sql/relational-databases/search/get-started-with-full-text-search


SELECT * FROM MyTable WHERE 
Column1 LIKE '%word1%'
AND Column1 LIKE '%word2%'
AND Column1 LIKE  '%word3%'

изменить OR to AND на основе edit to question.


если вы просто хотите найти совпадение.

SELECT * FROM MyTable WHERE INSTR('word1 word2 word3',Column1)<>0

SQL Server:

CHARINDEX(Column1, 'word1 word2 word3', 1)<>0

чтобы получить точное соответствие. Пример (';a;ab;ac;',';b;') не будет соответствовать.

SELECT * FROM MyTable WHERE INSTR(';word1;word2;word3;',';'||Column1||';')<>0

Если вы используете База Данных Oracle тогда вы можете достичь этого, используя содержит запрос. Содержит запросы быстрее, чем запрос like.

Если вам нужны все слова

SELECT * FROM MyTable WHERE CONTAINS(Column1,'word1 and word2 and word3', 1) > 0

Если вам нужно любое из слов

SELECT * FROM MyTable WHERE CONTAINS(Column1,'word1 or word2 or word3', 1) > 0

содержит индекс потребности типа контекст на своей колонке.

CREATE INDEX SEARCH_IDX ON MyTable(Column) INDEXTYPE IS CTXSYS.CONTEXT

почему бы вместо этого не использовать "in"?

Select *
from table
where columnname in (word1, word2, word3)

SELECT * FROM MyTable WHERE Column1 Like "*word*"

это отобразит все записи, где column1 имеет частичное значение содержит word.


попробуйте использовать "tesarus search" в полнотекстовом индексе в MS SQL Server. Это намного лучше, чем использовать "%" в поиске, если у вас есть миллионы записей. tesarus имеют небольшое количество потребления памяти, чем другие. попробуйте найти эту функцию:)


лучший способ это сделать полнотекстовый индекс для столбца в таблице и используйте contain вместо LIKE

SELECT * FROM MyTable WHERE 
contains(Column1 , N'word1' )
AND contains(Column1 , N'word2' )
AND contains(Column1 , N'word3' )

один из самых простых способов достичь того, что упоминается в вопросе, - использовать содержит С рядом или '~'. Например, следующие запросы дадут нам все столбцы, которые конкретно включают word1, word2 и word3.

SELECT * FROM MyTable WHERE CONTAINS(Column1, 'word1 NEAR word2 NEAR word3')

SELECT * FROM MyTable WHERE CONTAINS(Column1, 'word1 ~ word2 ~ word3')

кроме того, CONTAINSTABLE возвращает ранг для каждого документа на основе близости "word1", "word2" и "word3". Например, если документ содержит предложение "word1-это word2 и word3", его ранжирование будет высокий, потому что термины ближе друг к другу, чем в других документах.

еще одна вещь, которую я хотел бы добавить, это то, что мы также можем использовать proximity_term для поиска столбцов, где слова находятся внутри определенного расстояния между ними внутри фразы столбца.


DECLARE @SearchStr nvarchar(100)
SET @SearchStr = ' '



CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))

SET NOCOUNT ON

DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
SET  @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

WHILE @TableName IS NOT NULL

BEGIN
    SET @ColumnName = ''
    SET @TableName = 
    (
        SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
        FROM     INFORMATION_SCHEMA.TABLES
        WHERE         TABLE_TYPE = 'BASE TABLE'
            AND    QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
            AND    OBJECTPROPERTY(
                    OBJECT_ID(
                        QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
                         ), 'IsMSShipped'
                           ) = 0
    )

    WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)

    BEGIN
        SET @ColumnName =
        (
            SELECT MIN(QUOTENAME(COLUMN_NAME))
            FROM     INFORMATION_SCHEMA.COLUMNS
            WHERE         TABLE_SCHEMA    = PARSENAME(@TableName, 2)
                AND    TABLE_NAME    = PARSENAME(@TableName, 1)
                AND    DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar', 'int', 'decimal')
                AND    QUOTENAME(COLUMN_NAME) > @ColumnName
        )

        IF @ColumnName IS NOT NULL

        BEGIN
            INSERT INTO #Results
            EXEC
            (
                'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) FROM ' + @TableName + ' (NOLOCK) ' +
                ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
            )
        END
    END   
END

SELECT ColumnName, ColumnValue FROM #Results

DROP TABLE #Results

select * from table where name regexp '^word[1-3]$'

или

select * from table where name in ('word1','word2','word3')