Ich brauche eine Auswahl, die Ergebnisse wie folgt liefert:
SELECT * FROM MyTable WHERE Column1 CONTAINS 'Word1 Word2 Word3'
Und ich brauche alle Ergebnisse, d. H. Dazu gehören Zeichenfolgen mit "Word2 Word3 Word1" oder "Word1 Word3 Word2" oder einer beliebigen anderen Kombination der drei.
Alle Wörter müssen im Ergebnis sein.
Eher langsame, aber Arbeitsmethode, um any of words einzubeziehen:
SELECT * FROM mytable
WHERE column1 LIKE '%Word1%'
OR column1 LIKE '%Word2%'
OR column1 LIKE '%Word3%'
Wenn Sie alle Wörter benötigen, verwenden Sie Folgendes:
SELECT * FROM mytable
WHERE column1 LIKE '%Word1%'
AND column1 LIKE '%Word2%'
AND column1 LIKE '%Word3%'
Wenn Sie etwas schnelleres wollen, müssen Sie die Volltextsuche untersuchen. Dies ist für jeden Datenbanktyp sehr spezifisch.
Wenn Sie LIKE
verwenden, um festzustellen, ob eine Zeichenfolge eine Unterzeichenfolge einer anderen Zeichenfolge ist, müssen Sie die entsprechenden Zeichen in der Suchzeichenfolge mit Escapezeichen versehen.
Wenn Ihr SQL-Dialekt CHARINDEX
unterstützt, ist es viel einfacher, ihn stattdessen zu verwenden:
SELECT * FROM MyTable
WHERE CHARINDEX('Word1', Column1) > 0
AND CHARINDEX('Word2', Column1) > 0
AND CHARINDEX('Word3', Column1) > 0
Denken Sie auch daran, dass diese und die Methode in der akzeptierten Antwort nur die Übereinstimmung der Teilzeichenfolge und nicht die Wortübereinstimmung abdecken. So würde zum Beispiel die Zeichenfolge 'Word1word2Word3'
noch übereinstimmen.
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
Anstelle von SELECT * FROM MyTable WHERE Column1 CONTAINS 'Word1 Word2 Word3'
, Hinzufügen Und dazwischen Wörter wie:
SELECT * FROM MyTable WHERE Column1 CONTAINS 'Word1 And Word2 And Word3'
weitere Informationen finden Sie hier https://msdn.Microsoft.com/en-us/library/ms187787.aspx
UPDATE
Verwenden Sie zum Auswählen von Phrasen doppelte Anführungszeichen wie:
SELECT * FROM MyTable WHERE Column1 CONTAINS '"Phrase one" And Word2 And "Phrase Two"'
p.s. Sie müssen zunächst die Volltextsuche für die Tabelle aktivieren, bevor Sie Schlüsselwörter enthalten. Weitere Informationen finden Sie hier 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
in AND
geändert, basierend auf Bearbeitung in Frage.
Wenn Sie Oracle Database verwenden, können Sie dies mit contains query erreichen. Enthält Abfragen sind schneller als Abfragen.
Wenn Sie alle Wörter brauchen
SELECT * FROM MyTable WHERE CONTAINS(Column1,'Word1 and Word2 and Word3', 1) > 0
Wenn Sie eines der Wörter brauchen
SELECT * FROM MyTable WHERE CONTAINS(Column1,'Word1 or Word2 or Word3', 1) > 0
Enthält den Index des Typs CONTEXT in Ihrer Spalte.
CREATE INDEX SEARCH_IDX ON MyTable(Column) INDEXTYPE IS CTXSYS.CONTEXT
Wenn Sie nur eine Übereinstimmung finden möchten.
SELECT * FROM MyTable WHERE INSTR('Word1 Word2 Word3',Column1)<>0
SQL Server :
CHARINDEX(Column1, 'Word1 Word2 Word3', 1)<>0
Um genau übereinstimmen zu können. Beispiel (';a;ab;ac;',';b;')
wird keine Übereinstimmung finden.
SELECT * FROM MyTable WHERE INSTR(';Word1;Word2;Word3;',';'||Column1||';')<>0
versuchen Sie, die "Tesarus-Suche" im Volltextindex in MS SQL Server zu verwenden. Dies ist viel besser als die Verwendung von "%" bei der Suche, wenn Sie Millionen von Datensätzen haben. tesarus hat einen geringen Speicherbedarf als die anderen .. _. Versuchen Sie, diese Funktionen zu suchen :)
SELECT * FROM MyTable WHERE Column1 Like "*Word*"
Dadurch werden alle Datensätze angezeigt, bei denen column1
einen Teilwert enthält, der Word
enthält.
am besten erstellen Sie einen Volltextindex für eine Spalte in der Tabelle und verwenden Sie statt LIKE
SELECT * FROM MyTable WHERE
contains(Column1 , N'Word1' )
AND contains(Column1 , N'Word2' )
AND contains(Column1 , N'Word3' )
Eine der einfachsten Möglichkeiten, um zu erreichen, was in der Frage erwähnt wird, ist die Verwendung von ENTH&AUML;LT mit NEAR oder '~'. Die folgenden Abfragen geben uns beispielsweise alle Spalten an, die speziell Word1, Word2 und Word3 enthalten.
SELECT * FROM MyTable WHERE CONTAINS(Column1, 'Word1 NEAR Word2 NEAR Word3')
SELECT * FROM MyTable WHERE CONTAINS(Column1, 'Word1 ~ Word2 ~ Word3')
Darüber hinaus gibt CONTAINSTABLE einen Rang für jedes Dokument basierend auf der Nähe von "Word1", "Word2" und "Word3" zurück. Wenn ein Dokument beispielsweise den Satz "Das Wort1 ist Wort2 und Wort3" enthält, wäre seine Rangfolge hoch, da die Begriffe näher aneinander liegen als in anderen Dokumenten.
Eine andere Sache, die ich gerne hinzufügen möchte, ist, dass wir auch mit dem Zusatz_term Spalten suchen können, deren Wörter sich innerhalb eines bestimmten Abstands zwischen ihnen innerhalb der Spaltenphrase befinden.
Dies sollte im Idealfall mit Hilfe der SQL Server-Volltextsuche bei Verwendung von ..__ erfolgen. Wenn Sie dies jedoch aus irgendeinem Grund nicht in Ihrer Datenbank ausführen können, finden Sie hier eine leistungsintensive Lösung: -
-- table to search in
CREATE TABLE dbo.myTable
(
myTableId int NOT NULL IDENTITY (1, 1),
code varchar(200) NOT NULL,
description varchar(200) NOT NULL -- this column contains the values we are going to search in
) ON [PRIMARY]
GO
-- function to split space separated search string into individual words
CREATE FUNCTION [dbo].[fnSplit] (@StringInput nvarchar(max),
@Delimiter nvarchar(1))
RETURNS @OutputTable TABLE (
id nvarchar(1000)
)
AS
BEGIN
DECLARE @String nvarchar(100);
WHILE LEN(@StringInput) > 0
BEGIN
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));
INSERT INTO @OutputTable (id)
VALUES (@String);
END;
RETURN;
END;
GO
-- this is the search script which can be optionally converted to a stored procedure /function
declare @search varchar(max) = 'infection upper acute genito'; -- enter your search string here
-- the searched string above should give rows containing the following
-- infection in upper side with acute genitointestinal tract
-- acute infection in upper teeth
-- acute genitointestinal pain
if (len(trim(@search)) = 0) -- if search string is empty, just return records ordered alphabetically
begin
select 1 as Priority ,myTableid, code, Description from myTable order by Description
return;
end
declare @splitTable Table(
wordRank int Identity(1,1), -- individual words are assinged priority order (in order of occurence/position)
Word varchar(200)
)
declare @nonWordTable Table( -- table to trim out auxiliary verbs, prepositions etc. from the search
id varchar(200)
)
insert into @nonWordTable values
('of'),
('with'),
('at'),
('in'),
('for'),
('on'),
('by'),
('like'),
('up'),
('off'),
('near'),
('is'),
('are'),
(','),
(':'),
(';')
insert into @splitTable
select id from dbo.fnSplit(@search,' '); -- this function gives you a table with rows containing all the space separated words of the search like in this e.g., the output will be -
-- id
-------------
-- infection
-- upper
-- acute
-- genito
delete s from @splitTable s join @nonWordTable n on s.Word = n.id; -- trimming out non-words here
declare @countOfSearchStrings int = (select count(Word) from @splitTable); -- count of space separated words for search
declare @highestPriority int = POWER(@countOfSearchStrings,3);
with plainMatches as
(
select myTableid, @highestPriority as Priority from myTable where Description like @search -- exact matches have highest priority
union
select myTableid, @highestPriority-1 as Priority from myTable where Description like @search + '%' -- then with something at the end
union
select myTableid, @highestPriority-2 as Priority from myTable where Description like '%' + @search -- then with something at the beginning
union
select myTableid, @highestPriority-3 as Priority from myTable where Description like '%' + @search + '%' -- then if the Word falls somewhere in between
),
splitWordMatches as( -- give each searched Word a rank based on its position in the searched string
-- and calculate its char index in the field to search
select myTable.myTableid, (@countOfSearchStrings - s.wordRank) as Priority, s.Word,
wordIndex = CHARINDEX(s.Word, myTable.Description) from myTable join @splitTable s on myTable.Description like '%'+ s.Word + '%'
-- and not exists(select myTableid from plainMatches p where p.myTableId = myTable.myTableId) -- need not look into myTables that have already been found in plainmatches as they are highest ranked
-- this one takes a long time though, so commenting it, will have no impact on the result
),
matchingRowsWithAllWords as (
select myTableid, count(myTableid) as myTableCount from splitWordMatches group by(myTableid) having count(myTableid) = @countOfSearchStrings
)
, -- trim off the CTE here if you don't care about the ordering of words to be considered for priority
wordIndexRatings as( -- reverse the char indexes retrived above so that words occuring earlier have higher weightage
-- and then normalize them to sequential values
select s.myTableid, Priority, Word, ROW_NUMBER() over (partition by s.myTableid order by wordindex desc) as comparativeWordIndex
from splitWordMatches s join matchingRowsWithAllWords m on s.myTableId = m.myTableId
)
,
wordIndexSequenceRatings as ( -- need to do this to ensure that if the same set of words from search string is found in two rows,
-- their sequence in the field value is taken into account for higher priority
select w.myTableid, w.Word, (w.Priority + w.comparativeWordIndex + coalesce(sequncedPriority ,0)) as Priority
from wordIndexRatings w left join
(
select w1.myTableid, w1.priority, w1.Word, w1.comparativeWordIndex, count(w1.myTableid) as sequncedPriority
from wordIndexRatings w1 join wordIndexRatings w2 on w1.myTableId = w2.myTableId and w1.Priority > w2.Priority and w1.comparativeWordIndex>w2.comparativeWordIndex
group by w1.myTableid, w1.priority,w1.Word, w1.comparativeWordIndex
)
sequencedPriority on w.myTableId = sequencedPriority.myTableId and w.Priority = sequencedPriority.Priority
),
prioritizedSplitWordMatches as ( -- this calculates the cumulative priority for a field value
select w1.myTableId, sum(w1.Priority) as OverallPriority from wordIndexSequenceRatings w1 join wordIndexSequenceRatings w2 on w1.myTableId = w2.myTableId
where w1.Word <> w2.Word group by w1.myTableid
),
completeSet as (
select myTableid, priority from plainMatches -- get plain matches which should be highest ranked
union
select myTableid, OverallPriority as priority from prioritizedSplitWordMatches -- get ranked split Word matches (which are ordered based on Word rank in search string and sequence)
),
maximizedCompleteSet as( -- set the priority of a field value = maximum priority for that field value
select myTableid, max(priority) as Priority from completeSet group by myTableId
)
select priority, myTable.myTableid , code, Description from maximizedCompleteSet m join myTable on m.myTableId = myTable.myTableId
order by Priority desc, Description -- order by priority desc to get highest rated items on top
--offset 0 rows fetch next 50 rows only -- optional paging