问题
I have a Rails app and a column that contains an array like ["manager", "engineer"]
etc. and a where statement like this:
where("? = ANY roles", query)
which works find if I pass a single value for query. I want to be able to pass multiple values. I did some Googling and an simple solution was found:
where("? && roles", query )
except that if I pass something in like "['admin', 'guest']"
I get this error:
PG::InvalidTextRepresentation: ERROR: malformed array literal: "['admin', 'guest']"
LINE 1: .... $1 AND ('[''admin'...
^
DETAIL: "[" must introduce explicitly-specified array dimensions.
I suspect that there is some weird quote escaping issue but I can't figure it out. Those error messages results in a bunch of JSON Q&As but nothing that jumps out with a solution.
UPDATE
I always seem to find a clue after posting a question - I tried:
where("'{guest, admin}'::text[] && roles", query )
and it works - I still don't really know why but it does. Now I can't see how to get the ?
back in there now so I can search on it.
UPDATE 2
I took the first answer below and did a bit of refactoring to get what I think is a simple elegant solution:
where("'{#{roles}}'::text[] && roles")
This way I can pass a simple text string to my application helper that this where clause sits. It handles single and multiple queries.
回答1:
You're almost always better off using the array constructor syntax for arrays. From the fine manual:
4.2.12. Array Constructors
An array constructor is an expression that builds an array value using values for its member elements. A simple array constructor consists of the key word
ARRAY
, a left square bracket[
, a list of expressions (separated by commas) for the array element values, and finally a right square bracket]
. For example:SELECT ARRAY[1,2,3+4]; array --------- {1,2,7} (1 row)
ActiveRecord will expand an array value for a placeholder into a comma delimited list and that's exactly what the array[...]
syntax wants between the brackets. So you'd say:
where('array[?] && roles', query)
This even does the right thing if query
is a single value.
As far as your UPDATE goes, this:
'{guest, admin}'::text[]
is a string literal ('{guest, admin}'
) followed by a type cast (::
) to an array-of-text (text[]
). The '{...}'
syntax inside the string is another form of an array that is easy to read but a hassle to properly build; the fine manual also covers this form:
8.15.2. Array Value Input
To write an array value as a literal constant, enclose the element values within curly braces and separate them by commas.
I use the array[...]
version exclusively because it is easier to work with and more explicit as to what type the array elements are.
回答2:
Edit
DO NOT do what this answer suggests since it is dangerous and fragile. It was one of those things I really did not think through and regret posting in public
You want your array literal to be formatted like '{"admin", "guest"}'
Response to edited OP
query_terms = ["admin", "guest"]
query = "{#{ query_terms.map {|term| %Q("#{ term }") }.join(",") }}"
where("? && roles", query)
来源:https://stackoverflow.com/questions/34735673/postgresql-comparing-arrays-results-in-malformed-array-literal-error