2014-03-26 44 views
2

我正在使用SQL Server 2012.我需要使用單個文本字段實現搜索功能。跨多個表的SQL簡單搜索功能

比方說,我有如下表:

-------------------------------------------------------------------------------- 
FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR  
-------------------------------------------------------------------------------- 
John  Doe   Boston  2005  Mc Donald 
Marc  Forestier Bruxelle 2010  Private bank  
Céline  Durand  Paris  1999  Food SA  
Simon  Forestier Toulouse 2001  Forestier SARL 
John  Smith  New York 1992  Events Org. 
Sonia  Grappe  Toulon  2010  Forestier SARL 
-------------------------------------------------------------------------------- 

行爲如下:

  • 所有關鍵詞(空格隔開)必須上搜索所有列。
  • 一個LIKE應適用於每一個字
  • 如果只能用一個詞搜索,返回包含如果幾個單詞進行搜索這個詞
  • 所有記錄,只返回的記錄包含的不同詞數量最多(見「弗賴斯」下面的例子)
  • 我需要一個查詢,沒有TSQL

我嘗試了很多東西,但它並不像看起來那麼簡單。

一些例子:

「約翰」:

------------------------------------------------------------------------------- 
FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR 
------------------------------------------------------------------------------- 
John  Doe   Boston  2005  Mc Donald 
John  Smith  New York 1992  Events Org. 
------------------------------------------------------------------------------- 

「李四」:

------------------------------------------------------------------------------- 
FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR 
------------------------------------------------------------------------------- 
John  Doe   Boston  2005  Mc Donald 
------------------------------------------------------------------------------- 

「弗賴斯」:

------------------------------------------------------------------------------- 
FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR 
------------------------------------------------------------------------------- 
Marc  Forestier Bruxelle 2010  Private bank 
Simon  Forestier Toulouse 2001  Forestier SARL 
Sonia  Grappe  Toulon  2010  Forestier SARL 
------------------------------------------------------------------------------- 

「2010年xelle」 :

FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR 
-------------------------------------------------------------------------------- 
Marc  Forestier Bruxelle 2010  Private bank 
-------------------------------------------------------------------------------- 

本示例使用單個表;實際上,我的5個專欄來自4個不同的表格,所以實施全文搜索會稍微複雜一點!

+1

「我需要單個查詢,沒有TSQL」是什麼意思?爲什麼不顯示你嘗試過的許多事情中的一個或兩個。 –

+1

聽起來像全職搜索的工作。 http://technet.microsoft.com/en-us/library/ms142571.aspx –

+0

@KarlKieninger對不起,我的意思是沒有動態查詢,因爲我需要使用表值函數來運行查詢。 – Yann39

回答

0

這裏一個辦法。

我已將搜索限制爲6個單詞。 對於每個單詞,我檢查它是否存在於連接的列中。 每當在其中找到一個單詞時,通過添加+1來獲得每條記錄的「分數」。 我將返回記錄得分最高的記錄。

功能:

CREATE FUNCTION [dbo].[SEARCH_SINGLE] (
    @langId INT = 4, 
    @searchString VARCHAR(MAX) = NULL 
) 
RETURNS TABLE 
AS 
RETURN 
WITH words AS (
    SELECT Name as Val, ROW_NUMBER() OVER(ORDER BY Name) as Num FROM [dbo].splitstring(@searchString, ' ') 
), 
results AS (
    SELECT DISTINCT 
     ... 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 1 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END + 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 2 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END + 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 3 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END + 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 4 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END + 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 5 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END + 
     CASE WHEN EXISTS(SELECT 1 FROM words WHERE Num = 6 AND (ISNULL(a.[FIRSTNAME], '') + ' ' + ISNULL(a.[LASTNAME], '') + ' ' + ISNULL(c.[CITY], '') + ' ' + ISNULL(j.[PROMO_YEAR], '') + ' ' + ISNULL(e.[EMPLOYOR], '')) like '%'+Val+'%') THEN 1 ELSE 0 END as Nb 
    FROM 
     ... 
    WHERE 
     ... 
) 
SELECT 
    ... 
FROM 
    results 
WHERE 
    Nb = (SELECT MAX(Nb) FROM results) 
    AND Nb <> 0 

評論?

2

如何添加其他字段例如包含來自其他字段的所有信息的文本字段。

FIRSTNAME LASTNAME CITY  PROMOYEAR EMPLOYOR SEARCHFIELD 
John  Doe   Boston  2005  Mc Donald John Doe Boston 2005 Mc Donald 

並且在該字段上進行搜索。這不是優雅的,但它可以工作。

添加如下:

我不認爲SQL語法支持所有您的需要,但你可以做其他的解決辦法。創建一個表,其中包括所有你想要搜索的詞:

create table searchtable 
(
rowid int, --key to the id for the row in your table 
mothertableName varchar(), -- name of the table if necessary 
motherfieldName varchar(), -- name of field 
word varchar() -- the actual word to be searchable 
) 

的搜索詞,並在那裏他們擁有最大的發生:

SELECT * FROM myTable WHERE id IN(
    SELECT rid as id, MAX(c) FROM (
     SELECT rowid as rid, COUNT(rowid) as c FROM Searchtable WHERE word IN ('john','doe') 
    ) 
) 

上面的SQL肯定不會工作,但我希望你瞭解我提議的內容。你應該得到一行你的搜索詞最多的數字。但SQL中的'IN'運算符要求您創建一些動態SQL。

正如你所寫,你已經嘗試了幾乎所有的東西,我認爲SQL不能單獨做。

+0

你能提供一個查詢例子嗎?我無法設法找到這個解決方案... – Yann39

+0

我已經添加了一些我的第一個答案。往上看。 –

+0

你給了我一些想法!所以我終於找到了一個解決方案,我將它作爲答案發布,因爲我認爲這是一個更好的解決方案,它涵蓋了所有最初的要求。 – Yann39

2

這似乎是Sql Full Text Indexing的設計目的。

AFAIK全文索引不適用於數字類型,所以您可能需要爲任何日期或數字類型添加計算列,例如,如果PromoYear是數字:

ALTER TABLE MyTable 
    ADD TextPromoYear AS CAST(PromoYear AS NVARCHAR(4)) 
    PERSISTED; 

你需要安裝在數據庫中全文目錄:

CREATE FULLTEXT CATALOG CAT_MyCat AS DEFAULT; 

假設你有一個名爲PK_MyTable一個主鍵,創建全文索引:

CREATE FULLTEXT INDEX ON MyTable(FirstName, LastName, City, TextPromoYear, 
           Employer) 
KEY INDEX PK_MyTable; 
如果運氣好的話,您可以使用[`CONTAINS`](http://technet.microsoft.com/en-us/library/ms187787.aspx)或` FREETEXT`,如: SELECT * FROM MYTABLE WHERE CONTAINS((名字,姓氏,市,TextPromoYear,僱主), '爲OR 2010或xelle') 查詢語法不正是你想要,但是您可以根據`CONTAINS`的要求,將您想要的'空格分隔'查詢調整爲'和'。

編輯

這是不是很容易,因爲這。通配符*只能用作後綴,並且還需要彙總列才能在所有列中進行搜索。

完整的條款:

SELECT * 
FROM mytable 
WHERE CONTAINS(*, 'John and Doe'); 

對於部分搜索,您可能需要使用香草LIKE用於測試未知前綴(*xelle)訴諸混合:

SELECT * 
FROM mytable 
WHERE CONTAINS(*, '"for*" and 2010') AND SearchableComputedColumn like '%elle%'; 

Updated SqlFiddle here

+0

我認爲這是解決最初問題的正確方法;)但是我正在尋找更快/更簡單的解決方案。我簡化了我的例子,但實際上我的5個專欄來自4個不同的表格,我認爲這對我們的需求來說太複雜了。 – Yann39