让我根据下面的例子描述问题。 让我们说有一个字符串" abc12345" (可能是任何!!!)并且有一个表mytable,其列为mycolumn of varchar(100)。
有些行以最后一个字符结尾5 有些行以最后一个字符45结尾 有些行以最后一个字符345结束 没有以最后一个字符2345结尾的行。
在这种情况下,应选择这些行:
SELECT * FROM mytable WHERE mycolumn LIKE "%345"
那是因为" 345"是" abc12345"最长的子串。至少出现一次作为mycolumn列中至少一个字符串的右子字符串。 任何想法如何在一个查询中写入? 谢谢。
答案 0 :(得分:2)
这是一种蛮力方法:
select t.*
from (select t.*,
dense_rank() over (order by (case when mycolumn like '%abc12345' then 1
when mycolumn like '%bc12345' then 2
when mycolumn like '%c12345' then 3
when mycolumn like '%12345' then 4
when mycolumn like '%2345' then 5
when mycolumn like '%345' then 6
when mycolumn like '%45' then 7
when mycolumn like '%5' then 8
end)
) as seqnum
where mycolumn like '%5' -- ensure at least one match
from t
) t
where seqnum = 1;
然后启发这样的事情:
select t.*
from (select t.*, max(i) over () as maxi
from t join
(select str, generate_series(1, length(str)) as i
from (select 'abc12345' as str) s
) s
on left(t.mycolumn, i) = left(str, i)
) t
where i = maxi;
答案 1 :(得分:1)
如果你不能重组表格,我会这样解决问题:
在C中编写聚合UDF LONGEST_SUFFIX_MATCH(col, str)
(参见MySQL源代码sql/udf_example.c
中的示例,搜索avgcost
)
SELECT @longest_match:=LONGEST_SUFFIX_MATCH(mycol, "abcd12345") FROM mytbl; SELECT * FROM mytbl WHERE mycol LIKE CONCAT('%', SUBSTR("abcd12345", -@longest_match))
如果你可以重组表,我还没有一个完整的解决方案,但首先我要通过反转字符串(通过mycol_rev
函数)添加一个特殊列REVERSE()
并创建一个键,然后使用该键进行查找。我有时间会发布一个完整的解决方案。
更新
如果您可以添加带有键的反转列:
只要没有太多的行返回,此解决方案应该非常快。我们将总共有O(log(L))查询,其中L是搜索字符串的长度,每个搜索字符串是B树搜索,只读取一行,然后是另一个B树搜索,索引读取只有所需的行。
答案 2 :(得分:1)
有趣的谜题:))
这里最难的问题是找到与后缀模式匹配的目标后缀的长度。
在MySQL中,您可能需要使用生成系列或UDF。其他人已经提出了这些。
在PostgreSQL和其他提供基于regexp的子字符串的系统中,您可以使用以下技巧:
select v,
reverse(
substring(
reverse(v) || '#' || reverse('abcdefg')
from '^(.*).*#\1.*'
)) res
from table;
它的作用是:
#
放在重要的字符串之间,你需要一个字符串中不存在的字符。substring
从正则表达式中提取匹配项
^
(.*)
.*
#
(.*)
之后出现与#
匹配的相同字符串。所以我们使用\1
.*
一旦你有了最长的后缀,找到最大长度,然后找到所有后缀为该长度的字符串是微不足道的。
这是使用PostgreSQL的SQLFiddle: