PostgreSQL搜索文本在具有类型数组的列中

时间:2014-09-26 18:51:59

标签: postgresql

我在PostgreSQL中有一个用于存储电影细节的表,

film_id serial NOT NULL,
title text,
language text,
directors text[]

我可以写一个查询来查找所有具有导演姓名' ab'

的电影
SELECT * FROM films  where  'ab' like any(films.directors)

但是如何编写一个查询来搜索表格以获得所有电影的导演名称以' ab'开头,此查询不会给我任何结果

 SELECT * FROM films  where  'ab%' like any(films.directors)

3 个答案:

答案 0 :(得分:1)

我可以想到两种不同的方式(它们都不是很优雅):

取消数组,然后使用LIKE搜索元素,如果您需要再次将结果作为数组,则需要进行聚合(这意味着添加的列数不仅仅是导向器和film_id会很复杂:

select film_id, array_agg(name) as directors
from (
  SELECT film_id, unnest(directors) as name
  FROM films  
) t
where name like 'ab%'
group by film_id;

另一个选项(同样慢)可能是创建一个带有分隔符的长字符串,然后在该字符串中搜索:

select *
from films
where '###'||array_to_string(directors, '###') like '%###ab%'

将分隔符预先添加到字符串中可确保每个条目都以分隔符开头,条件like '%###ab%'仅匹配实际以ab开头的名称。

答案 1 :(得分:1)

还有另一种方式。原因是,您的原始计划无效,原因是array comparison expressions只能使用运算符&运算符右侧的数组表达式:

<expression> operator ANY|SOME|ALL (<array expression>)

所有模式匹配运算符都工作颠倒(右侧有模式) - 你也可以使用它,但只有你有一个模式数组,你要测试它又一个字符串。这通常不是那么有用,但你可以make some operators反转:

CREATE OR REPLACE FUNCTION reverse_like(text, text) RETURNS BOOLEAN LANGUAGE SQL AS 'SELECT $2 LIKE $1';
CREATE OR REPLACE FUNCTION reverse_ilike(text, text) RETURNS BOOLEAN LANGUAGE SQL AS 'SELECT $2 ILIKE $1';
CREATE OR REPLACE FUNCTION reverse_similarto(text, text) RETURNS BOOLEAN LANGUAGE SQL AS 'SELECT $2 SIMILAR TO $1';
CREATE OR REPLACE FUNCTION reverse_posix_match(text, text) RETURNS BOOLEAN LANGUAGE SQL AS 'SELECT $2 ~ $1';
CREATE OR REPLACE FUNCTION reverse_posix_imatch(text, text) RETURNS BOOLEAN LANGUAGE SQL AS 'SELECT $2 ~* $1';

CREATE OPERATOR ~~> (PROCEDURE = reverse_like, LEFTARG = text, RIGHTARG = text);
CREATE OPERATOR ~~*> (PROCEDURE = reverse_ilike, LEFTARG = text, RIGHTARG = text);
CREATE OPERATOR ~~~> (PROCEDURE = reverse_similarto, LEFTARG = text, RIGHTARG = text);
CREATE OPERATOR ~> (PROCEDURE = reverse_posix_match, LEFTARG = text, RIGHTARG = text);
CREATE OPERATOR ~*> (PROCEDURE = reverse_posix_imatch, LEFTARG = text, RIGHTARG = text);

之后,您可以使用ANY / SOME / ALL数组比较:

SELECT *
FROM   films
WHERE  '^ab' ~> any(films.directors);

SELECT *
FROM   films
WHERE  'ab%' ~~> any(films.directors);

SELECT *
FROM   films
WHERE  'ab%' ~~~> any(films.directors);

SQLFiddle

答案 2 :(得分:0)

SELECT * 
FROM films
where directors like 'ab%';

应该能满足您的要求。注意LIKE运算符的表达式是如何从它们所在的顺序切换的。

这是postgresql 9的SELECT文档的link,其中有一个查询示例,如上例所示。

ANY需要根据http://www.postgresql.org/docs/9.0/static/functions-subquery.html

的子查询