【问题标题】:A more efficient way of doing a 'single word match' check between two tables在两个表之间进行“单字匹配”检查的更有效方法
【发布时间】:2016-10-13 11:08:56
【问题描述】:

我有一个 SQL 查询,它返回表 1 中的所有记录,其中字段中的一个完整单词与表 2 中的字段名称匹配。例如,如果我在表 2 中有一个名为“brown”的字段,则字段名称在 "the quick brown fox" 的表 1 中将在结果中返回,但不会返回 "thequickbrownfox" 的字段名称,因为它在字段名。

select distinct [SpecNumber], [SpecName], sc.[SpecCrosscheckName] from [SpecSummary] ss
    INNER JOIN [SpecCrosscheck] sc
        on ss.[SpecName] = sc.[SpecCrosscheckName] or
           ss.[SpecName] like '% ' + sc.[SpecCrosscheckName] + ' %' or
           ss.[SpecName] like '% ' + sc.[SpecCrosscheckName] or
           ss.[SpecName] like sc.[SpecCrosscheckName] + ' %'
        order by sc.[SpecCrosscheckName]

这会按预期返回结果,但内部连接是复杂的,因此需要 3 多分钟才能运行。有没有更有效的方法来获得相同的结果?据我所知,没有办法将 like 语句合并为一个,而且我不相信这会提高性能。

我已经研究过使用CONTAINS,但我不相信字段名称可以用作此函数中的搜索条件?

额外信息: SpecCrosscheck 只包含一个字段,一个单词名称列表(“James”、“Boris”等)。 SpecSummary 中的“SpecName”字段包含全名(例如“David James”、“Joe Bloggs”)。我想返回 SpecSummary 中的所有结果,其中全名中的一个单词与 SpecCrosscheckName 中的任何记录相同(因此对于上面的示例,将返回“David James”,但不会返回“Joe Bloggs”)。

【问题讨论】:

  • 我认为这里非常需要样本数据及其对预期结果的解释。如果可以的话,请提供一些
  • @Suraz 进行了编辑 - 希望可以澄清事情。

标签: sql sql-server


【解决方案1】:

这个:

ss.[SpecName] like '%' + sc.[SpecCrosscheckName] + '%'

与所有其余部分的组合相同,因此仅此而已。

编辑:没有发现空格,我的错。

【讨论】:

  • 这不适用于名称完全匹配的位置,或者匹配的字段位于最开始或结束的位置(因为条件搜索值两侧的空白区域)。
  • 你错了@finjo,试试 JohnHC 说的话......你会得到与查询相同的结果
  • 除了完全匹配因为前后加空格,没有?
  • 我试过了,但没有。正如我所说,从我的问题中的示例开始,字段值 "brown fox" 不会与“brown”匹配,因为查询变为 codess.[SpecName] 喜欢'% brown %'code - 因为开头没有空格所以不会返回。
  • @JohnHC 'thequickbrownfox' 现在将被归类为我不想要的有效。我自己也一直在同一个圈子里转:(
【解决方案2】:

尝试添加前导和尾随空格,

select distinct [SpecNumber], [SpecName], sc.[SpecCrosscheckName] from [SpecSummary] ss
    INNER JOIN [SpecCrosscheck] sc
        on ' '+ ss.[SpecName] +' ' like '% ' + sc.[SpecCrosscheckName] + ' %' 
        order by sc.[SpecCrosscheckName]

虽然这将按预期工作,但您的原始查询会运行得更快!

【讨论】:

    【解决方案3】:

    试试下面的脚本。

    select distinct [SpecNumber], [SpecName], sc.[SpecCrosscheckName] from [SpecSummary] ss
        INNER JOIN [SpecCrosscheck] sc
            on  LTRIM(RTRIM(ss.[SpecName]))  like '%' +sc.[SpecCrosscheckName]+ '%' 
            order by sc.[SpecCrosscheckName]
    

    【讨论】:

    • 遇到了与我在这里对苏拉兹的回答相同的问题......性能明显更好,但它不再删除部分结果,这是我对原始查询的意图。我正在努力想一种方法来合并 LTRIM/RTRIM 并确保同时只有单个单词匹配。
    【解决方案4】:

    我认为您可以通过删除单词之间的空格来比较列,所以如果我是对的,那么您可以通过如下 REPLACE 函数实现:

    REPLACE(ss.[SpecName], ' ', '') = REPLACE(sc.[SpecCrosscheckName], ' ', '')
    

    或者,您也可以使用下面的部分比较

    REPLACE(ss.[SpecName], ' ', '') LIKE '%' + REPLACE(sc.[SpecCrosscheckName], ' ', '') + '%'
    

    完整的查询如下:

    SELECT DISTINCT [SpecNumber], [SpecName], sc.[SpecCrosscheckName] 
    FROM [SpecSummary] ss
    INNER JOIN [SpecCrosscheck] sc 
    ON REPLACE(ss.[SpecName], ' ', '') LIKE '%' + REPLACE(sc.[SpecCrosscheckName], ' ', '') + '%'
    ORDER BY sc.[SpecCrosscheckName]
    

    【讨论】:

    • 这将返回字段跨两个单词的结果,因此例如字段值“棕色”将被视为“棕色”的匹配项。然而,这似乎在正确的轨道上,因为返回 3815 个结果需要 2 分半钟(相比之下,旧查询需要 3 分 10 秒才能返回 919)......我将努力调整它以尝试获取摆脱“跨两个词的搜索结果”问题......如果您对我如何做到这一点有任何想法,请告诉我。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 2021-07-30
    相关资源
    最近更新 更多