我目前正在研究Postgres SQL查询,该查询将检查以任意随机顺序匹配空格分隔字符串(3个字)的行。
例如,我想查找匹配“lorem ipsum dolor”的行,它应该返回行ID 0.
+----+-------------------+
| id | sentence |
| 0 | lorem dolor ipsum |
| 1 | lorem ipsum |
| 2 | ipsum dolor |
| 3 | ipsum dolor |
+----+-------------------+
因此必须满足以下条件:
如果我是正确的,这应该导致3 * 3 * 3 = 27种可能的格式。但是,这可以想象,当使用更多单词时,这相当密集。如何在不锤击服务器的情况下实现这一目标,或者找到正确的方向。
答案 0 :(得分:1)
with t(s) as (values
('lorem dolor ipsum'),
('lorem ipsum'),
('ipsum dolor'),
('ipsum dolor')
)
select *
from t
where
(
select string_agg(lower(s), ' ' order by s)
from regexp_split_to_table(s, '\s+') s(s)
)
=
(
select string_agg(lower(s), ' ' order by s)
from regexp_split_to_table('lorem ipsum dolor', '\s+') s(s)
)
;
s
-------------------
lorem dolor ipsum
http://www.postgresql.org/docs/current/static/functions-aggregate.html http://www.postgresql.org/docs/current/static/functions-string.html#FUNCTIONS-STRING-OTHER
答案 1 :(得分:1)
Clodoaldo Neto描述的这种方法很适合对单词进行排序。如果性能对您至关重要,您甚至可以为此创建索引以提高查找速度。首先创建自定义函数sortwords
:
CREATE OR REPLACE FUNCTION sortwords (words text) RETURNS text AS
$$ SELECT string_agg(lower(s), ' ' order by s)
FROM regexp_split_to_table($1, '\s+') s(s) $$
LANGUAGE sql IMMUTABLE;
关键字IMMUTABLE
指定函数结果完全依赖于它的参数,因此该函数适用于创建索引。
然后,创建索引:
CREATE INDEX mytable_sortwords ON mytable (sortwords(sentence));
并执行以下选择:
SELECT * FROM mytable WHERE sortwords(sentence) = sortwords('some words');
这样做的好处是,单词的排序(可以非常省时)每行只执行一次(无论是创建索引还是插入行)。
答案 2 :(得分:0)
实现此目的的一种方法是中断搜索文本,然后将其添加为以下过滤器:
select * from test
where sentence like '%lorem%'
and sentence like '%ipsum%'
and sentence like '%dolor%';
这将以任何顺序获得包含这三个单词的所有句子。 看到它在这里工作:http://sqlfiddle.com/#!15/28ac1/3
修改强>
为了在任何情况下获得结果,您必须将lower
函数添加到字段sentence
,如下所示:
select * from test
where lower(sentence) like '%lorem%'
and lower(sentence) like '%ipsum%'
and lower(sentence) like '%dolor%';
请在此处查看:http://sqlfiddle.com/#!15/6dfb9/1
编辑2
正如OP在评论中所说,他只需要只包含三个搜索词的注册表,我会采用这种方法:
select * from test
where position('lorem' in lower(sentence))>0
and position('ipsum' in lower(sentence))>0
and position('dolor' in lower(sentence))>0
and array_length(regexp_split_to_array(sentence, E'\\s+')::text[],1) =
array_length(regexp_split_to_array('lorem ipsum dolor', E'\\s+')::text[],1)