sql - 如何在 PostgreSQL 中获取字符串中正则表达式匹配的位置?

标签 sql regex database postgresql

我有一个包含书名的表格,我想选择标题与正则表达式匹配的书籍,并根据正则表达式在标题中的位置对结果进行排序。

单个词搜索很容易。例如

TABLE book
id   title
1    The Sun
2    The Dead Sun
3    Sun Kissed

在将查询发送到 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

但是如果搜索词有多个词,我想将包含搜索词中所有词的标题与它们之间的任何词进行匹配,并像以前一样按位置排序,所以我需要一个返回正则表达式位置的函数,我在官方 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

我没有找到任何类似于 ???REGEXP_POSITION_FUNCTION??? 的函数,您有什么想法吗?

最佳答案

(许多)方法之一:删除从匹配项开始的字符串的其余部分并测量截断字符串的长度:

SELECT id, title
FROM   book
WHERE  title ILIKE '%deep%space%'
ORDER  BY length(regexp_replace(title, 'deep.*space.*', '','i'));

在 WHERE 子句中使用 ILIKE,因为这通常更快(这里也一样)。
还要注意 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'));

您可以在手册中找到上述所有内容的文档 herehere .

-> SQLfiddle展示所有。

关于sql - 如何在 PostgreSQL 中获取字符串中正则表达式匹配的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21104366/

相关文章:

mysql - 结合查询进行查询优化

mysql - 从 MySQL 中选择唯一的数据集

java - java中的正则表达式忽略

c# - 将连接字符串与后端代码分离

regex - 如何处理 Google App Engine app.yaml 中的尾部斜杠

ruby - 如何使用正则表达式解析网页中的文章?

java - Android SQLite数据库主键查询

php - Laravel 多模型关系返回计数

php - 更改数据库中图像的路径

php - 为什么我的 MySQL 连接很慢?