Postgresql: comparing arrays results in “malformed array literal” error

匿名 (未验证) 提交于 2019-12-03 01:26:01

问题:

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) 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!