Ответ 1
Для SQL Server попробуйте следующее:
SELECT Word, COUNT(Word) * 10 AS WordCount
FROM SourceTable
INNER JOIN SearchWords ON CHARINDEX(SearchWords.Word, SourceTable.Name) > 0
GROUP BY Word
Я хочу сравнить отдельные слова от ввода пользователя на отдельные слова из столбца в моей таблице.
Например, рассмотрим эти строки в моей таблице:
ID Name
1 Jack Nicholson
2 Henry Jack Blueberry
3 Pontiac Riddleson Jack
Учтите, что пользовательский ввод "Pontiac Jack". Я хочу назначить весы/ранги для каждого совпадения, поэтому я не могу использовать обложку LIKE (WHERE Name LIKE @SearchString).
Если Pontiac присутствует в любой строке, я хочу присудить ему 10 очков. Каждый матч для Джека получает еще 10 очков и т.д. Так что строка 3 получит 20 очков, а строки 1 и 2 получат 10.
Я разделил пользовательский ввод на отдельные слова и сохранил их во временную таблицу @SearchWords (Word).
Но я не могу понять способ иметь инструкцию SELECT, которая позволяет мне объединить это. Может быть, я собираюсь сделать это неправильно?
Cheers, WT
Для SQL Server попробуйте следующее:
SELECT Word, COUNT(Word) * 10 AS WordCount
FROM SourceTable
INNER JOIN SearchWords ON CHARINDEX(SearchWords.Word, SourceTable.Name) > 0
GROUP BY Word
Как насчет этого? (это синтаксис MySQL, я думаю, вам нужно заменить CONCAT и сделать это с помощью +)
SELECT names.id, count(searchwords.word) FROM names, searchwords WHERE names.name LIKE CONCAT('%', searchwords.word, '%') GROUP BY names.id
Тогда у вас будет результат SQL с идентификатором таблицы имен и количеством слов, соответствующих этому идентификатору.
Вы можете сделать это через общее табличное выражение, которое будет определять вес. Например:
--** Set up the example tables and data
DECLARE @Name TABLE (id INT IDENTITY, name VARCHAR(50));
DECLARE @SearchWords TABLE (word VARCHAR(50));
INSERT INTO @Name
(name)
VALUES ('Jack Nicholson')
,('Henry Jack Blueberry')
,('Pontiac Riddleson Jack')
,('Fred Bloggs');
INSERT INTO @SearchWords
(word)
VALUES ('Jack')
,('Pontiac');
--** Example SELECT with @Name selected and ordered by words in @SearchWords
WITH Order_CTE (weighting, id)
AS (
SELECT COUNT(*) AS weighting
, id
FROM @Name AS n
JOIN @SearchWords AS sw
ON n.name LIKE '%' + sw.word + '%'
GROUP BY id
)
SELECT n.name
, cte.weighting
FROM @Name AS n
JOIN Order_CTE AS cte
ON n.id = cte.id
ORDER BY cte.weighting DESC;
Используя этот метод, вы также можете применить значение к каждому поисковому слову, если хотите. Поэтому вы можете сделать Джека более ценным, чем Pontiac. Это будет выглядеть примерно так:
--** Set up the example tables and data
DECLARE @Name TABLE (id INT IDENTITY, name VARCHAR(50));
DECLARE @SearchWords TABLE (word VARCHAR(50), value INT);
INSERT INTO @Name
(name)
VALUES ('Jack Nicholson')
,('Henry Jack Blueberry')
,('Pontiac Riddleson Jack')
,('Fred Bloggs');
--** Set up search words with associated value
INSERT INTO @SearchWords
(word, value)
VALUES ('Jack',10)
,('Pontiac',20)
,('Bloggs',40);
--** Example SELECT with @Name selected and ordered by words and values in @SearchWords
WITH Order_CTE (weighting, id)
AS (
SELECT SUM(sw.value) AS weighting
, id
FROM @Name AS n
JOIN @SearchWords AS sw
ON n.name LIKE '%' + sw.word + '%'
GROUP BY id
)
SELECT n.name
, cte.weighting
FROM @Name AS n
JOIN Order_CTE AS cte
ON n.id = cte.id
ORDER BY cte.weighting DESC;
Мне кажется, что лучше всего будет поддерживать отдельную таблицу со всеми отдельными словами. Например:
ID Word FK_ID
1 Jack 1
2 Nicholson 1
3 Henry 2
(etc)
Эта таблица будет обновляться с помощью триггеров, и у вас будет некластеризованный индекс в "Word", "FK_ID". Тогда SQL для создания ваших весов будет простым и эффективным.
Как насчет чего-то подобного....
Select id, MAX(names.name), count(id)*10 from names
inner join @SearchWords as sw on
names.name like '%'+sw.word+'%'
group by id
предполагая, что таблица с именами называется "именами".