【问题标题】:Search function, SQL Server搜索功能,SQL Server
【发布时间】:2009-11-22 15:24:21
【问题描述】:

我正在我的网站上创建一个小型搜索功能,这可以在系统中搜索文章。每篇文章都有一组与之关联的关键字,这些关键字存储在 SQL Server 数据库中。

这是桌子:

CREATE TABLE [dbo].[SearchWords] (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ArticleID] [int] NOT NULL,
    [SearchWord] [nvarchar](20) NOT NULL,
    CONSTRAINT [PK_SearchWords] PRIMARY KEY CLUSTERED 
        ([ID] ASC) 
        WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE = OFF, 
              IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
              ALLOW_PAGE_LOCKS  = ON)
        ON [PRIMARY]
) ON [PRIMARY]

每篇文章可以有无限数量的关键字。现在我的问题是搜索本身。 例如,当用户键入:

法国演员

我希望系统找到所有带有关键字 France 和 actor 的文章(仅一次 DISTINCT)。我将搜索条件作为 varchar(用空格分隔)传递给存储过程。然后我用以下函数拆分单词:(Erland Sommarskog)http://www.sommarskog.se/arrays-in-sql-2005.html#iter-list-of-strings

然后我如何将条件词与搜索词匹配并仅获得不同的文章 ID?

我正在使用类似的东西,只是我无法理解如何匹配所有关键字。如果只输入一个关键字,则此方法有效。如果用户输入多个,那么即使文章包含所有涉及的关键字,它也不会返回任何内容。

declare @temp nvarchar(50)
set @temp = 'France actors'

SELECT DISTINCT Article.ArticleID 
FROM Article
INNER JOIN SearchWords 
    ON Article.ArticleID = SearchWords.ArticleID
JOIN iter_charlist_to_tbl(@temp, DEFAULT) s 
    ON SearchWords.SearchWord = s.nstr

有什么想法吗?

【问题讨论】:

    标签: sql sql-server search join


    【解决方案1】:

    SQL server 有你可以使用的全文搜索。您可以使用 CONTAINs 和 CONTAINSTABLE 或 FREETEXT 和 FREETEXTTable 来代替自己创建搜索功能

    Way of searching 30,000 SQL Records

    【讨论】:

    • 全文也很好,因为您还可以使用它来匹配相关或听起来像您的单词的单词,因此“drive”也可以匹配“drives”等 - 如果您愿意的话。跨度>
    • 不允许?很遗憾,因为我认为创建一个比使用 FTS 更快的自定义解决方案会很困难。
    【解决方案2】:

    首先,您链接的 UDF 的默认分隔符是 , 字符,而不是空格。因此,使用默认分隔符,您将得到一个包含两个单词的单行。 (调试提示:当出现问题时,将其拆开。在这种情况下,您应该执行select * from UDF(@temp, DEFAULT) 以查看表格是否正确。)

    假设您想继续使用该 UDF,并且您想要匹配任何搜索词(但不一定是全部)的文章,那么这些内容应该是正确的:

    declare @temp nvarchar(50)
    set @temp = 'France actors'
    
    SELECT DISTINCT 
      a.ArticleID 
    FROM 
      Article a
      JOIN SearchWords sw ON a.ArticleID = sw.ArticleID
    WHERE
      exists (
        select 
          1 
        from 
          iter_charlist_to_tbl(@temp, ' ') s 
        where
          s.nstr = sw.SearchWord
      )
    

    如果您将参数更改为 UDF,您的内部连接方法应该也可以正常工作。

    【讨论】:

    • 这将如何确保您匹配Franceactors
    • 啊,对。我快速浏览问题的错误。开始重写它,但我得到了和你上面一样的解决方案,没有理由发两次。
    • 我稍微更改了您的代码以返回匹配的关键字数量。这样我就可以首先显示产生最高关键字匹配的结果。有没有办法捕获这产生的记录数?我将它与返回记录的 C# SQL-to-Linq 类结合起来。但是,我还希望它返回一个带有匹配记录数的 OUTPUT int。我需要向用户展示找到的总行数,并从使用 .Skip(x) 行数中受益。
    • 返回的记录数通常是客户端统计,通过检查结果集的适当属性得到
    【解决方案3】:

    您可以使用 group by 来做到这一点,然后要求找到的关键字数量等于关键字的总数:

    SELECT SearchWords.ArticleID 
    FROM SearchWords 
    INNER JOIN iter_charlist_to_tbl(@temp, DEFAULT) s 
        ON SearchWords.SearchWord = s.nstr
    GROUP BY SearchWords.ArticleID
    HAVING COUNT(*) = (
        select count(*) from iter_charlist_to_tbl(@temp, DEFAULT)
    )
    

    顺便说一句,如果您只是在寻找 ArticleID,则不需要加入文章,因此我删除了该表。

    【讨论】:

      【解决方案4】:

      试试这样的...

      SET @Temp = ','+replace(@temp,' ',',')+','
      
      SELECT DISTINCT article.ArticleID
      FROM article
      JOIN SearchWords ON Article.ArticleID=SearchWords.ArticleID
      WHERE CharIndex(','+SearchWords.SearchWord+',',@temp) > 0
      

      我不确定您如何将输入文本分隔成单独的单词,因此您可能需要更改逗号分隔符,或者执行更多代码来构建逗号分隔的字符串,但是一旦构建,连接和上面的 where 子句应该可以解决问题...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-04
        • 2018-10-17
        • 1970-01-01
        • 1970-01-01
        • 2021-01-20
        • 1970-01-01
        相关资源
        最近更新 更多