【问题标题】:How to make a sql search query more powerful?如何让一个sql搜索查询更强大?
【发布时间】:2010-10-15 08:46:38
【问题描述】:

我写了这个 sql 查询来在一个表中搜索:

SELECT * FROM TableName WHERE Name LIKE '%spa%'

表格包含这些行,例如:

  1. 太空公司。
  2. 温泉度假村。
  3. 温泉酒店。
  4. 备件。
  5. WithoutTheKeyword。

我想知道如何编辑这个查询,让它返回这样排序的结果:

2 温泉度假村

3 温泉酒店

1 个太空公司

4 备件

表示先包含确切单词然后包含类似单词的项目。

【问题讨论】:

    标签: sql mysql sql-server sql-server-2005 tsql


    【解决方案1】:

    您意识到,我猜,您的架构几乎消除了此类查询的索引的任何用处?

    一个大问题是您的“LIKE '%spa%'”。任何以通配符开头的“LIKE”键都是自动表扫描。


    编辑: 我读到您的问题是说有一个字段名称,其字段值类似于“1 Space Company”、“2 Spa 度假村”等,数字后跟单词。而且您需要在搜索键前面加上通配符才能跳过数字部分。 (这是为了澄清我的第一条评论。)我猜对了吗?

    【讨论】:

    • “1 Space Company”的一个字段值?为什么不是这两个字段——“1”和“Space Company”?仅在名称部分上创建索引是不可能的,而且它显然是两个不同的数据元素,或者您不会询问对部分字段进行排序。
    • 一个大问题是你的“LIKE '%spa%'”。任何以通配符开头的“LIKE”键都是自动表扫描。
    • 我不确定 CHARINDEX('spa ', Name) > 0 会更好。仅仅因为它是表扫描并不意味着它是错误的。我认为无论如何这是一个搜索类型的查询,“Spa”实际上是一个@FindMe 参数。尝试提供帮助而不是吝啬如何?
    • 他正在帮助教导所使用的技术和底层设计是糟糕的。将您的搜索基于这样的查询就像在 Jello 上建立您的家庭基础。
    • 我不同意。扫描类型的查询有时是可以的,只要它有一个狭窄的焦点并且不是主要的搜索方式。哦,是的,另外 - 他错了。
    【解决方案2】:

    您基本上需要(精确地)定义您的排名函数到底是什么。如果您有一排是“The Spa”怎么办。或“spa.com”?定义好之后,您需要将该逻辑放入您的 ORDER BY 子句中。例如:

    SELECT
        name
    FROM
        Some_Table
    WHERE
        name LIKE '%spa%'
    ORDER BY
        CASE
            WHEN name LIKE '% ' + @search_word + ' %' THEN 1   -- Notice the spaces
            ELSE 2
        END,
        name
    

    或者,您可以编写一个排名函数并使用它:

    SELECT
        name
    FROM
        Some_Table
    WHERE
        name LIKE '%' + @search_word + '%'
    ORDER BY
        dbo.GetNameMatchRank(name, @search_word)
    

    在非常大的结果集上的性能可能不会太好,因此这种方法取决于您预期的搜索结果大小。

    【讨论】:

      【解决方案3】:

      离开上面的例子,至少在 MSSQL2005 中将 CLUSTERED 更改为 NONCLUSTERED 会使其进行表扫描。 CLUSTERED 为您提供索引查找。看起来它符合问题的条件。

      创建表 tblTest(ID INT, colname VARCHAR(20) ) 创建集群索引 tstidx1_tblTest ON tblTest(colname); 插入 tblTest SELECT 1,“太空公司” 插入 tblTest SELECT 2,“温泉度假村” 插入 tblTest SELECT 3,“温泉酒店” 插入 tblTest SELECT 4,“备件” 插入 tblTest SELECT 5,'WithoutTheKeyword' SELECT * FROM tblTest WHERE colname LIKE 'Spa%' ORDER BY DIFFERENCE(colname,'Spa') DESC; 删除表 tblTest

      【讨论】:

        【解决方案4】:

        类似

        Select * from TableName where Name Like 'Spa%'
        ORDER BY case when soundex(name) = soundex('Spa') then '1' else soundex(name) end
        

        应该可以正常工作。

        其实这样会更好

        Select * from TableName where Name Like 'Spa%'
        ORDER BY DIFFERENCE(name, 'Spa') desc;
        

        FWIW 我做了一些快速测试,如果“名称”在非集群索引中,SQL 将使用索引并且不进行表扫描。此外,LIKE 似乎比 charindex 使用更少的资源(返回不太理想的结果)。在 sql 2000 上测试。

        【讨论】:

        • 你写“soundex(name) = soundex('Spa')”,在 soundex(name) 中的名字是什么,或者我应该这样写吗?
        • 对于您编写的第一个脚本,它总是给我这个错误:“将 varchar 值 'L000' 转换为数据类型 int 时转换失败。”
        • 但是您通过删除前导通配符从根本上改变了问题。
        • 也许,我认为是多余的。阿姆雷尔加里?当我有机会时,我会看看这是否会产生差异。但是,您的答案虽然可能不正确,但可以用一种不那么居高临下的语气来表达,甚至更有帮助。我只是想保护新人。
        • 你在推断我无意暗示的事情。我试图从怀疑中受益,而不是“很明显你甚至没有意识到……”其他回答似乎说至少有几个人是这样读的。虽然这总是一个很好的提醒,要更加努力。
        【解决方案5】:

        以下应该做必要的事情,但它效率低下,做两个全表选择,而且它还依赖于你的完全匹配被空格分隔。我认为全文索引会有所帮助,但这有其自身的开销。

        select distinct * from
        (
        Select * from TableName 
           where CHARINDEX('spa ', Name) > 0
           or CHARINDEX(' spa', Name) > 0
        Union
        Select * from TableName 
          where Name Like '%spa%'
        )
        

        【讨论】:

          【解决方案6】:

          这应该可行:

          Select * from TableName where Name Like '%spa%'
          ORDER BY Name
          

          【讨论】:

          • 问题是他想按匹配的质量排序,而不是匹配。按名称订购不会做他想做的事。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-09-25
          • 2017-01-03
          • 1970-01-01
          • 2016-04-18
          • 1970-01-01
          • 2017-03-06
          • 2016-03-08
          相关资源
          最近更新 更多