Reputation: 2702
I have a table in PostgreSQL for storing details of films,
film_id serial NOT NULL,
title text,
language text,
directors text[]
I can write a query to find all films having a director name 'ab'
SELECT * FROM films where 'ab' like any(films.directors)
But How can I write a query to search the table to get all films having a director name starting with 'ab',this query does not giving me any result
SELECT * FROM films where 'ab%' like any(films.directors)
Upvotes: 0
Views: 175
Reputation: 36214
There is another way too. The reason, your original plan could not work, is because the array comparison expressions can only use an operator & an array expression on the right side of the operator:
<expression> operator ANY|SOME|ALL (<array expression>)
And all the pattern matching operators work reversed (on the right side there are the pattern) -- you could use that too, but only if you have a pattern array, which you want to test again a single string. this is usually not so useful, but you can make some operators which work reversed:
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);
After that, you can use the ANY
/SOME
/ALL
array comparisons:
SELECT *
FROM films
WHERE '^ab' ~> any(films.directors);
SELECT *
FROM films
WHERE 'ab%' ~~> any(films.directors);
SELECT *
FROM films
WHERE 'ab%' ~~~> any(films.directors);
Upvotes: 1
Reputation: 732
SELECT *
FROM films
where directors like 'ab%';
should get you what you request. Notice how the expressions surronding the LIKE
operator are switched from the order they were in.
Here is a link to the SELECT
documentation for postgresql 9 which has an example of query using like as show above in my example.
ANY
needs a subquery according to http://www.postgresql.org/docs/9.0/static/functions-subquery.html
Upvotes: 0
Reputation:
I can think of two different ways (none of them really elegant):
Unnest the array and then search on the elements using LIKE
, if you need the result as an array again, you need to aggregate (which means adding more columns than just the directors and the film_id
is going to be complicated:
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;
Another option (equally slow) might be to create a long string with a delimiter out of the array and then search inside that string:
select *
from films
where '###'||array_to_string(directors, '###') like '%###ab%'
Prepending the delimiter to the string ensures that every entry starts with the delimiter and the condition like '%###ab%'
will only match names that actually start with ab
.
Upvotes: 1