2009-07-08 78 views
0

我正努力再次用SQL執行搜索功能。SQL算法麻煩 - for循環添加和篩選結果

基本上我想要一個存儲過程,將字符串分解成單詞,然後對每個單詞我想檢查使用全文搜索,如果它是在任何2表。

如果在這些表中找到結果,則應將它們添加到爲其他單詞找到的任何結果中,並返回記錄位於這兩個集合中的集合。

因此,這裏是我的算法

if null return all restaurants 

declare results = empty 

for each word 
if in restaurant.name or cuisine.name 
    addRowsToResults 
else if in restaurant.city 
    addRowsToResults 
else if in restaurant.postcode 
    addRowsToResults 


addRowsToResults 
results = (results + new results) where a match is in both 

我不知道從哪裏開始的這一點,我已搜查谷歌的年齡,但作爲SQL中的初學者我可能會丟失一些術語。

也是這甚至是做這種事情的最佳方式?

感謝任何幫助。

編輯: 只是爲了給更多的信息。城市,郵政編碼和名稱都是餐館表中的所有nvarchar字段。料理名稱位於不同的餐桌中,並通過另一張餐桌連接到餐館,因爲餐廳可以提供多種類型的美食。

所有這些字段都有全文搜索索引。

+0

想要「AND」或「OR」嗎?您聲明「AND」,但這意味着搜索詞必須位於餐廳,美食,城市和郵編區域。因此,對於所有在「21201」中爲「21201」命名的「21201」餐館,在晚餐時間服務「21201」的MD(郵政編碼「21201」),這將適用於...... – GalacticCowboy 2009-07-08 22:56:37

+0

您並不需要郵編和全文的全文普通的舊索引將起作用。你也在使用全文來處理它沒有設計的東西,它被設計爲索引大塊文本,而不是2,3個字。 – 2009-07-08 22:59:56

+0

我想先檢查一下這個詞是否在餐廳名稱或美食中(例如,餐館可能被稱爲最佳中文),如果不匹配,我想檢查該單詞是否在城市中,如果仍然沒有匹配,我想檢查如果是郵政編碼。 這樣就可以在用戶將文字輸入到文本框中時對結果進行過濾。 – ddd 2009-07-08 23:00:01

回答

1

這不是SQL的工作方式。你可以得到一些相同的功能,但它看起來不像你所問的那樣;你正在寫更自然的程序風格。

「添加結果」的一件事是試圖將不同的事物集中到一個集合中。你是 - 我認爲 - 要​​求餐館和美食以及城市和郵編全部進入同一個集合,並且唯一一種集合SQL(粗略地說)就是表格,在一張表格中,所有行都具有相同的類型。

但也許餐館和美食和城市和郵政編碼都是同一個表的字段?好了,那麼,對於一個給定詞,你可以說

SELECT * 
FROM your_table 
WHERE restaurant like "%" + word + "%" 
OR  cuisine like "%" + word + "%" 
OR  city  like "%" + word + "%" 
OR  postcode like "%" + word + "%"; 

它啓動時要匹配多個單詞變得複雜;這個答案是作爲一個起點;也許一旦你更熟悉SQL,你可以問問題更容易回答的問題。祝你好運!

更新根據你的表說明

SELECT r.* 
FROM  restaurant r 
INNER JOIN link  k ON k.restaurant_id = r.restaurant_id 
INNER JOIN cuisine c on c.cuisine_id = k.cuisine_id 
WHERE r.restaurant like "%" + word + "%" 
OR  c.name  like "%" + word + "%" 
OR  r.city  like "%" + word + "%" 
OR  r.postcode like "%" + word + "%"; 

而且不用擔心它記錄回來「第一」。你的數據庫會很快,這不應該成爲一個問題。

+0

這是與我之前所做的相似的事情,但我試圖做的事情是以任何順序匹配多個單詞inputed。因此,我的僞代碼中的if語句的順序。 美食是唯一的字段在不同的tabe,因爲它是通過另一張桌子連接作爲一家餐廳可以爲多種美食類型 – ddd 2009-07-08 22:51:22

0

即使我想,我也無法給你完整的故事 - 你沒有發佈表格定義或任何樣本數據。

這就是說,我會做出一些猜測。首先,我認爲你需要以基於集合的方式使用SQL。不要認爲按行處理 - 處理一個集合。然後將這些組合在一起。

1

有一個分詞function here。它返回一個你可以加入的表格。

您還應該調查metaphone或soundex,但是爲了支持您需要在單獨的表中預先索引數據,或者在單獨的字段和索引中預先計算每個單詞的metho或soundex代碼。

1

它看起來像你試圖採取程序方法,以基於集合的聲明性查詢語言。

首先,您可以使用表值用戶定義的函數將字符串拆分爲結果集。像下面的內容會做 -

CREATE function [dbo].[csl_to_table] (@list nvarchar(MAX)) 
RETURNS @list_table TABLE ([id] nvarchar(20)) -- set this to your maximum size string 
AS 
BEGIN 
    DECLARE  @index INT, 
       @start_index INT, 
       @id nvarchar(20) -- set this to your maximum size string 

    SELECT @index = 1 
    SELECT @start_index = 1 
    WHILE @index <= DATALENGTH(@list) 
    BEGIN 

     IF SUBSTRING(@list,@index,1) = ',' 
     BEGIN 

       SELECT @id = SUBSTRING(@list, @start_index, @index - @start_index) 
       INSERT @list_table ([id]) VALUES (@id) 
       SELECT @start_index = @index + 1 
     END 
     SELECT @index = @index + 1 
    END 
    SELECT @id = SUBSTRING(@list, @start_index, @index - @start_index) 
    INSERT @list_table ([id]) VALUES (@id) 
    RETURN 
END 

然後使用您的結果集,你可以加入到您要查詢的比賽,並返回匹配的一個結果表。

0

如果您正在尋找SQL中的For Each循環,大多數SQL方言都有Cursors,允許您使用某個查詢選擇所有記錄,然後使用Cursor遍歷記錄。

0

要使用全文搜索,您希望使用CONTAINS關鍵字。看看如何在網上使用它(我必須參加一個會議,或者我會舉一個例子)。

1

這裏是一個分裂的功能,有一個分隔符的可選參數...

CREATE FUNCTION [dbo].[fnSplit](@List VARCHAR(4000), @Delimiter CHAR(1) = ',') 
    RETURNS @Result TABLE (item VARCHAR(100)) 
    BEGIN 
     DECLARE @Item VARCHAR(100) 
     WHILE CHARINDEX(@Delimiter,@List,0) <> 0 
     BEGIN 
      SELECT @Item = SUBSTRING(@List,1,CHARINDEX(@Delimiter,@List,0)-1) 
       , @List = SUBSTRING(@List,CHARINDEX(@Delimiter,@List,0)+1,LEN(@List)) 

      IF LEN(@Item) > 0 
       INSERT INTO @Result 
        SELECT @Item 
     END 
     IF LEN(@List) > 0 
      INSERT INTO @Result 
       SELECT @List 
     RETURN 
    END 
GO 

然後你的查詢可以是這個樣子......

SELECT DISTINCT 
     'restaurants' AS [source] 
    , r.ID AS [ID] --Assuming ID is your primary key column 
    , r.name + '(' + r.city + ', ' + r.state + ')' AS [Description] 
FROM restaurants AS [r] 
JOIN [dbo].[fnSplit](@Query,' ') AS [terms] 
ON 
    ISNULL(r.name,'') 
    +','+ISNULL(r.city,'') 
    +','+ISNULL(r.postcode,'') LIKE '%'+terms.item+'%' 

UNION SELECT DISTINCT 
     'cuisine' AS [source] 
    , r.ID AS [ID] --Assuming ID is your primary key column 
    , r.name AS [Description] 
FROM cuisine AS [r] 
JOIN [dbo].[fnSplit](@Query,' ') AS [terms] 
ON 
    ISNULL(r.name,'') LIKE '%'+terms.item+'%' 

fnSplit功能將查詢條件分解爲表變量中的行並將其返回。選擇查詢然後加入到結果表中。查詢是不同的,因此無論查詢中有多少條件匹配,只返回一行的一個實例。連接條件可以很容易地分解爲一系列的AND/OR條件,但我認爲LIKE操作比串聯更昂貴,所以我只是連接列。

UPDATE

因爲全文索引啓用以下簡化查詢可以使用。

DECLARE @Phrase VARCHAR(4000) 
SELECT @Phrase = item + '" OR "' FROM [dbo].[fnSplit](@Query,' ') 
SET @Phrase = SUBSTRING(@Phrase,0,LEN(@Phrase)-6) 


SELECT DISTINCT 
     'restaurants' AS [source] 
    , r.ID AS [ID] --Assuming ID is your primary key column 
    , r.name + '(' + r.city + ', ' + r.state + ')' AS [Description] 
FROM restaurants AS [r] 
WHERE 
    CONTAINS(r.name,@Phrase) 
    OR CONTAINS(r.city,@Phrase) 
    OR CONTAINS(r.postcode,@Phrase) 

UNION SELECT DISTINCT 
     'cuisine' AS [source] 
    , r.ID AS [ID] --Assuming ID is your primary key column 
    , r.name AS [Description] 
FROM cuisine AS [r] 
WHERE CONTAINS(r.name,@Phrase)