Мне нужен выбор, который бы возвращал результаты, как это:
SELECT * FROM MyTable WHERE Column1 CONTAINS 'word1 word2 word3'
И мне нужны все результаты, т.е. это включает в себя строки с 'word2 word3 word1' или 'word1 word3 word2' или любую другую комбинацию из трех.
Все слова должны быть в результате.
Довольно медленный, но рабочий метод, чтобы включить любые слов:
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 СОДЕРЖАЩАЕТ '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"'
p.s. Вы должны сначала включить полнотекстовый поиск в таблице, прежде чем использовать ключевое слово. для получения более подробной информации см. здесь 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
на И
на основе редактирования на вопрос.
Если вы используете Oracle Database , вы можете достичь этого с помощью contains. Содержит запросы быстрее, чем как запрос.
Если вам нужны все слова
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
Содержит индекс необходимости типа CONTEXT в вашем столбце.
CREATE INDEX SEARCH_IDX ON MyTable(Column) INDEXTYPE IS CTXSYS.CONTEXT
Если вы просто хотите найти совпадение.
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
В идеале это должно быть сделано с помощью полнотекстового поиска на сервере sql при использовании. Однако, если по какой-то причине вы не можете заставить это работать на своей БД, вот решение для повышения производительности :-
- таблица для поиска в
СОЗДАТЬ ТАБЛИЦУ dbo.myTable
(
myTableId int NOT NULL IDENTITY (1, 1),
код varchar (200) НЕ NULL,
описание varchar (200) НЕ NULL - этот столбец содержит значения, в которых мы будем искать
) НА [ПРИЗРАВОЧНО]
ИДТИ
- функция разделения пространства, разделенная строкой поиска на отдельные слова
СОЗДАЙТЕ ФУНКЦИЮ [дбо].[fnSplit] (@StringInput nvarchar (max),
@Delimiter nvarchar (1))
ВОЗВРАЩАЕТСЯ @OutputTable TABLE (
id nvarchar (1000)
)
КАК
НАЧАТЬ
DECLARE @ String nvarchar (100) ;
КОГДА ЛЕН (@StringInput) > 0
НАЧАТЬ
SET @ String = LEFT (@StringInput, ISNULL (NULLIF (CHARINDEX (@Delimiter, @StringInput) - 1, -1),
LEN (@ StringInput))) ;
SET @ StringInput = SUBSTRING (@StringInput, ISNULL (NULLIF (CHARINDEX
(
@Delimiter, @StringInput
),
0
), LEN
(
@StringInput)
)
+ 1, LEN (@ StringInput)) ;
ВСТАВИТЬ В @OutputTable (id)
ЦЕННОСТИ (@ String) ;
КОНЕЦ;
ВОЗВРАТИТЬ;
КОНЕЦ;
ИДТИ
- это скрипт поиска, который можно при желании преобразовать в сохраненную процедуру / функцию
объявлять @search varchar (max) = 'инфекция верхнего острого генито'; - введите строку поиска здесь
- искомая строка выше должна давать строки, содержащие следующее
- инфекция в верхней части острой кишечной тракты
- острая инфекция верхних зубов
- острая кишечная боль
if (len (trim (@ search)) = 0) - если строка поиска пуста, просто верните записи в алфавитном порядке
начать
выберите 1 в качестве приоритета, myTableid, код, описание из порядка myTable по описанию
возвращение;
конец
объявить таблицу @splitTable (
wordRank int Identity (1,1), - отдельные слова имеют приоритетный порядок (в порядке возникновения / положения)
слово варчар (200)
)
объявлять таблицу @nonWordTable (- таблица для обрезания вспомогательных глаголов, предлогов и т. д. из поиска
id varchar (200)
)
вставить в значения @nonWordTable
('of')
('с')
('at')
('в')
('для')
('на')
('by')
('лайк')
('вверх')
('выкл')
('близ')
('is')
('есть')
(',')
(':')
(';')
вставить в @splitTable
выберите id из dbo.fnSplit (@search, ''); - эта функция дает вам таблицу со строками, содержащими все разделенные пробелами слова поиска, как в этом, например,., выход будет -
-- id
-------------
- инфекция
- верхний
- острый
- генито
удалить s из @splitTable s join @nonWordTable n в s.word = n.id; - обрезать не слова здесь
объявлять @countOfSearchStrings int = (выбрать count (слово) из @splitTable); - количество пробелов, разделенных словами для поиска
объявлять @highestPriority int = POWER (@countOfSearchStrings, 3) ;
с простыми метками как
(
выберите myTableid, @highestPriority в качестве приоритета в myTable, где Описание, например, @search - точные совпадения имеют наивысший приоритет
союз
выберите myTableid, @ highestPriority-1 в качестве приоритета в myTable, где Описание, например, @search + '%' - затем с чем-то в конце
союз
выберите myTableid, @ highestPriority-2 в качестве приоритета в myTable, где описание «%» + @search - затем с чем-то в начале
союз
выберите myTableid, @ highestPriority-3 в качестве приоритета в myTable, где описание «%» + @search + «%» - тогда, если слово падает где-то посередине
),
splitWordMatches as (- присваивает каждому искомому слову ранг, основанный на его положении в искомой строке
- и вычислить его индекс символов в поле для поиска
выберите myTable.myTableid, (@countOfSearchStrings - s.wordRank) в качестве Приоритета, s.word,
wordIndex = CHARINDEX (s.word, myTable.Description) из myTable join @splitTable s в myTable. Описание типа '%' + s.word + '%'
- и не существует (выберите myTableid из plainMatches p, где p.myTableId = myTable.myTableId) - не нужно изучать мои таблицы, которые уже были найдены в простых камнях, поскольку они имеют наивысший рейтинг
- хотя это занимает много времени, поэтому, комментируя это, не повлияет на результат
),
appingRowsWithAllWords as (
выберите myTableid, count (myTableid) в качестве myTableCount из группы splitWordMatches по (myTableid), имеющей count (myTableid) = @countOfSearchStrings
)
- обрежьте CTE здесь, если вас не волнует порядок слов, которые следует рассматривать как приоритетные
wordIndexRatings as (- обратные индексы символов, восстановленные выше, так что слова, происходящие ранее, имеют более высокую весомость
- и затем нормализуйте их до последовательных значений
выберите s.myTableid, Приоритет, слово, ROW_NUMBER () over (разделение по порядку s.myTableid по wordindex desc) в качестве сравнительного индекса WordIndex
из splitWordMatches s jointingRowsWithAllWords m на s.myTableId = m.myTableId
)
,
wordIndexSequenceRatings as (- необходимо сделать это, чтобы гарантировать, что если один и тот же набор слов из строки поиска будет найден в двух строках
- их последовательность в значении поля учитывается для более высокого приоритета
выберите w.myTableid, w.word, (w.Priority + w.comparativeWordIndex + coalesce (sequncedPriority, 0)) в качестве Приоритета
от wordIndexRatings w слева присоединиться
(
выберите w1.myTableid, w1.priority, w1.word, w1.comparativeWordIndex, count (w1.myTableid) как sequncedPriority
из wordIndexRatings w1 присоединиться к wordIndexRatings w2 на w1.myTableId = w2.myTableId и w1.Priority > w2.Priority и w1.comparativeWordIndex > w2.comparativeWordIndex
группа по w1.myTableid, w1.priority, w1.word, w1.comparativeWordIndex
)
squorizedPriority на w.myTableId = sequencedPriority.myTableId и w.Priority = sequencedPriority.Priority
),
preatializedSplitWordMatches as (- это вычисляет совокупный приоритет для значения поля
выберите w1.myTableId, sum (w1.Priority) в качестве общего приоритета из wordIndexSequenceRatings w1 присоединиться к wordIndexSequenceRatings w2 на w1.myTableId = w2.myTableId
где w1.word < > w2.word group by w1.myTableid
),
completeSet as (
выберите myTableid, приоритет из plainMatches - получите простые совпадения, которые должны быть наивысшим рейтингом
союз
выберите myTableid, GeneralPriority в качестве приоритета из preatizedSplitWordMatches - получите ранжированные совпадения слов (которые упорядочены на основе рангов слов в строке поиска и последовательности)
),
maximizedCompleteSet as (- установить приоритет значения поля = максимальный приоритет для этого значения поля
выберите myTableid, max (приоритет) в качестве приоритета в группе fullSet по myTableId
)
выберите приоритет, myTable.myTableid, код, описание из maximizedCompleteSet m присоединиться к myTable на m.myTableId = myTable.myTableId
порядок по приоритету desc, описание - заказ по приоритету desc, чтобы получить предметы с самым высоким рейтингом сверху
--offset 0 строк только для следующих 50 строк - необязательная пейджинг
лучший способ - сделать полнотекстовый индекс в столбце таблицы и использовать содержать вместо LIKE
SELECT * FROM MyTable WHERE
contains(Column1 , N'word1' )
AND contains(Column1 , N'word2' )
AND contains(Column1 , N'word3' )
почему бы не использовать "в" вместо этого?
Select *
from table
where columnname in (word1, word2, word3)
Один из самых простых способов достичь того, что упоминается в вопросе, - это использовать [СОДЕРЖАНИЕ][1] с NEAR или '~'. Например, следующие запросы дадут нам все столбцы, которые конкретно включают 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». Например, если документ содержит предложение «Слово 1 - это слово 2 и слово 3», его рейтинг будет высоким, поскольку термины ближе друг к другу, чем в других документах.
Еще одна вещь, которую я хотел бы добавить, это то, что мы также можем использовать saintinity_term, чтобы найти столбцы, в которых слова находятся на определенном расстоянии между ними внутри фразы столбца.
[1]: https://docs.microsoft.com/en-us/sql/t-sql/queries/contains-transact-sql?view = sql-server-2017
попробуйте использовать «поиск тезаруса» в полнотекстовом индексе в MS SQL Server. Это намного лучше, чем использовать «%» в поиске, если у вас есть миллионы записей. Тесар имеет небольшое количество памяти, чем другие. попробуйте поискать эту функцию :)
SELECT * FROM MyTable WHERE Column1 Like "*word*"
Это отобразит все записи, где column1
имеет частичное значение, содержащее word
.
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