rsl*_*lnx 5 regex sql database postgresql
我有一个带书名的表格,我想选择标题与正则表达式匹配的书籍,并按标题中正则表达式匹配的位置排序结果.
单词搜索很容易.例如
TABLE book
id title
1 The Sun
2 The Dead Sun
3 Sun Kissed
Run Code Online (Sandbox Code Playgroud)
我打算把.*
发送查询DB之前,字与字之间在客户端的搜索词,所以我会写在这里准备的正则表达式SQL.
SELECT book.id, book.title FROM book
WHERE book.title ~* '.*sun.*'
ORDER BY COALESCE(NULLIF(position('sun' in book.title), 0), 999999) ASC;
RESULT
id title
3 Sun Kissed
1 The Sun
2 The Dead Sun
Run Code Online (Sandbox Code Playgroud)
但是如果搜索词有多个单词,我想匹配标题,这些标题包含搜索词中的所有单词和它们之间的任何内容,并按照之前的位置排序,所以我需要一个返回正则表达式位置的函数,我没有在PostgreSQL官方文档中找到合适的一个.
TABLE books
id title
4 Deep Space Endeavor
5 Star Trek: Deep Space Nine: The Never Ending Sacrifice
6 Deep Black: Space Espionage and National Security
SELECT book.id, book.title FROM book
WHERE book.title ~* '.*deep.*space.*'
ORDER BY ???REGEXP_POSITION_FUNCTION???('.*deep.*space.*' in book.title);
DESIRED RESULT
id title
4 Deep Space Endeavor
6 Deep Black: Space Espionage and National Security
5 Star Trek: Deep Space Nine: The Never Ending Sacrifice
Run Code Online (Sandbox Code Playgroud)
我没有找到类似于??? REGEXP_POSITION_FUNCTION的任何功能???,你有什么想法吗?
执行此操作的一种方法(多种方法):删除从匹配项开始的字符串的其余部分并测量截断字符串的长度:
SELECT id, title
FROM book
WHERE title ILIKE '%deep%space%'
ORDER BY length(regexp_replace(title, 'deep.*space.*', '','i'));
Run Code Online (Sandbox Code Playgroud)
ILIKE
在 WHERE 子句中使用,因为这通常更快(并且在这里执行相同的操作)。
另请注意函数的第四个参数regexp_replace()
( 'i'
),以使其不区分大小写。
按照评论中的要求。
同时演示如何首先对匹配项NULLS LAST
进行排序(和)。
SELECT id, title
,substring(title FROM '(?i)(^.*)deep.*space.*') AS sub1
,length(substring(title FROM '(?i)(^.*)deep.*space.*')) AS pos1
,substring(title FROM '(?i)^.*(?=deep.*space.*)') AS sub2
,length(substring(title FROM '(?i)^.*(?=deep.*space.*)')) AS pos2
,substring(title FROM '(?i)^.*(deep.*space.*)') AS sub3
,position((substring(title FROM '(?i)^.*(deep.*space.*)')) IN title) AS p3
,regexp_replace(title, 'deep.*space.*', '','i') AS reg4
,length(regexp_replace(title, 'deep.*space.*', '','i')) AS pos4
FROM book
ORDER BY title ILIKE '%deep%space%' DESC NULLS LAST
,length(regexp_replace(title, 'deep.*space.*', '','i'));
Run Code Online (Sandbox Code Playgroud)
-> SQLfiddle演示了所有内容。