I want to use array_position
function in PostgreSQL (which takes array of some type and expression or value of the same type) for constructing query that returns rows in some arbitrary order (additional context: I want to enhance Ruby on Rails in_order_of
feature which is currently implemented via unreadable CASE
statement):
SELECT id, title, type
FROM posts
ORDER BY
array_position(ARRAY['SuperSpecial','Special','Ordinary']::varchar[], type),
published_at DESC;
The problem here is that requirement to do explicit type casting from type inferred by PostgreSQL from array literal (ARRAY['doh']
is text[]
) to type of expression (type
is varchar
here). While varchar
and text
are coercible to each other, PostgreSQL requires explicit type cast, otherwise if omit it (like in array_position(ARRAY['doh'], type)
) PostgreSQL will throw error (see this answer for details):
ERROR: function array_position(text[], character varying) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
While it is not a problem to specify explicit type cast in some static queries, it is problem in autogenerated queries when type of expression is unknown beforehand: array_position(ARRAY[1,2,3], id * 2)
(what type has id * 2
?)
I thought that pg_typeof()
could help me, but it seems that it can't be used neither in ::
operator nor in CAST
operator (I've seen information that both forms aren't function forms, but syntax constructs, see this question for details):
SELECT id, title, type
FROM posts
ORDER BY array_position(CAST(ARRAY['SpecialPost','Post','Whatever'] AS pg_typeof(type)), type), id;
ERROR: type "pg_typeof" does not exist
LINE 1: ...on(CAST(ARRAY['SpecialPost','Post','Whatever'] AS pg_typeof(...
Question:
How to do dynamic typecast to expression type (say, to type of "posts"."id" * 2
) in the same SQL query?
I would prefer to avoid extra roundtrip to database server (like executing SELECT pg_typeof("id" * 2) FROM "posts" LIMIT 1
and then using its result in generating of a new query) or writing some custom functions. Is it possible?