3

您将如何在 varchar 变量中搜索最长的匹配项?例如,表 GOB 具有以下条目:

magic_word |  prize
===================
         sh|  $0.20
        sha|  $0.40
       shaz|  $0.60
      shaza|  $1.50

我想编写一个 plpgsql 函数,它在其他参数中接受一个字符串作为输入(例如shazam),并返回 GOB 行上具有最长匹配子字符串的“奖品”列。在显示的示例中,这将$1.50在具有 magic_word 的行上shaza

我可以处理的所有函数格式,它只是匹配位。我想不出一个优雅的解决方案。我猜这可能真的很容易,但我正在摸不着头脑。我不知道一开始的输入字符串,因为它将来自另一个表的查询结果。

有任何想法吗?

4

2 回答 2

5

简单的解决方案

SELECT magic_word
FROM   gob
WHERE  'shazam' LIKE (magic_word || '%')
ORDER  BY magic_word DESC
LIMIT  1;

这是有效的,因为最长的匹配排在最后 - 所以我排序DESC并选择第一个匹配。

我从您的示例中假设您希望从字符串的开头匹配左锚定。如果您想匹配字符串中的任何位置(使用索引更昂贵,甚至更难备份),请使用:

...
WHERE  'shazam' LIKE ('%' || magic_word || '%')
...

SQL小提琴。

表现

查询不是sargable。如果您有其他信息(例如可以作为索引基础的最小长度)来减少要考虑的行数,这可能会有所帮助。它必须是让你在表格中占不到 5% 的标准才有效。因此,缩写(自然的最低选择)可能有用,也可能没有用。但是开头的两三个字母可能会有所帮助。

事实上,您可以反复优化它。类似于以下内容:
尝试使用 15 个字母的单词的部分索引+
如果找不到,请尝试 12 个字母+
如果找不到,请尝试 9 个字母+
...

我在 dba.SE 的相关答案中概述的一个简单案例:

另一种方法是使用三元索引。你需要额外的模块pg_trgm通常,您会在具有较长字符串的表中使用短模式进行搜索。但是三元组也适用于您的反向方法,但有一些限制。显然,您无法使用三元组在较长的字符串中间仅匹配两个字符的字符串...测试极端情况。
这里有很多关于 SO 的答案以及更多信息。例子:

先进的解决方案

考虑这个密切相关的问题下的整个搜索字符串表的解决方案。使用递归 CTE 实现:

于 2013-05-04T03:06:53.393 回答
1

怎么样

1

     select max(FOO.matchingValue)
     from
      (
        select magic_word as matchingValue
        from T
        where substr( "abracadabra", 1, length(magic_word)) = magic_word 
      )
      as FOO

2

select prize from
T
  join
  (
  select max(FOO.matchingValue) as MaxValue
     from
      (
         select magic_word as matchingValue
        from T
        where substr( "abracadabra", 1, length(magic_word)) = magic_word 
      )
      as FOO
) as BAR
on BAR.MaxValue = T.magic_word
于 2013-05-04T01:37:09.917 回答