2010-06-26 5 views
10

Chcę porównać poszczególne słowa od danych wprowadzanych przez użytkownika do poszczególnych słów z kolumny w mojej tabeli.SQL: Dzielenie kolumny na wiele słów w celu wyszukania wprowadzonego przez użytkownika

Na przykład, następujące wiersze w moim stole:

ID Name 
1 Jack Nicholson 
2 Henry Jack Blueberry 
3 Pontiac Riddleson Jack 

Uważają, że wejście użytkownika jest 'Pontiac Jack'. Chcę przypisać ciężary/rangi dla każdego meczu, więc nie mogę użyć koca LIKE (WHERE Name LIKE @SearchString).

Jeśli Pontiac jest obecny w dowolnym rzędzie, chcę przyznać mu 10 punktów. Każdy mecz dla Jacka dostaje kolejne 10 punktów, itd. Tak więc rząd 3 uzyskałby 20 punktów, a rzędy 1 i 2 otrzymałyby 10.

Podzielę dane użytkownika na poszczególne słowa i zapisałem je w tabeli tymczasowej @SearchWords (Słowo).

Ale nie mogę znaleźć sposobu, aby mieć instrukcję SELECT, która pozwala mi połączyć to. Może robię to w niewłaściwy sposób?

Cheers, WT

+1

Czy rozważałeś zastosowanie wyszukiwania pełnotekstowego SQL SErver? –

+0

Tak, mam - nie działało dobrze dla nas i bardzo trudno było dostosować go do naszych wymagań. –

+1

+1 dla wyszukiwania fullText - niekoniecznie SQL Server, ale na przykład lucene.net. –

Odpowiedz

1

Dla SQL Server, spróbuj tego:

SELECT Word, COUNT(Word) * 10 AS WordCount 
FROM SourceTable 
INNER JOIN SearchWords ON CHARINDEX(SearchWords.Word, SourceTable.Name) > 0 
GROUP BY Word 
+0

Ładne, eleganckie rozwiązanie. Wyobrażam sobie, że tabela OP musiałaby mieć coś łączącego poszczególne słowa z powrotem z oryginalną wyszukiwaną frazą - więc uzyskanie wyniku dla całej frazy byłoby tak proste, jak połączenie frazy z tym i zsumowanie liczby słów pogrupowanych według całej frazy. Ładna nazwa użytkownika btw ...jeden z moich ulubionych xkcds :) –

0

Co na ten temat? (Jest to składnia MySQL, myślę, że trzeba tylko wymienić CONCAT i zrobić z +)

SELECT names.id, count(searchwords.word) FROM names, searchwords WHERE names.name LIKE CONCAT('%', searchwords.word, '%') GROUP BY names.id 

Wtedy masz wynik SQL z ID nazwy stołem i liczby słów pasujących do tego id.

0

Można to zrobić za pomocą wspólnego wyrażenia tabeli, która działa na ważenie. Na przykład:

--** 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; 

Za pomocą tej techniki można również zastosować wartość do każdego wyszukiwanego słowa, jeśli chcesz. Więc możesz sprawić, by Jack był bardziej wartościowy niż Pontiac. To wyglądałoby mniej więcej tak:

--** 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;  
0

Wydaje mi się, że najlepszą rzeczą do zrobienia byłoby utrzymanie oddzielnego stołu z wszystkimi pojedynczymi słowami. Np:

ID  Word  FK_ID 
1  Jack  1 
2  Nicholson 1 
3  Henry  2 
(etc) 

Ta tabela będzie uaktualniane z wyzwalaczy, a chcesz mieć nieklastrowanym indeksu „Słowo”, „FK_ID”. Następnie SQL, aby uzyskać wasze wagi, byłby prosty i skuteczny.

0

Jak o coś takiego ....

Select id, MAX(names.name), count(id)*10 from names 
inner join @SearchWords as sw on 
    names.name like '%'+sw.word+'%' 
group by id 

zakładając, że tabela z nazwami zwanych "nazwiska".

Powiązane problemy