Rails 4使用数组数据类型错误查询postgresql列

kwy*_*g11 4 sql ruby-on-rails postgresql-9.2 ruby-on-rails-4

我试图在Rails 4中查询带有postgresql数组数据类型的列的表.

这是表模式:

create_table "db_of_exercises", force: true do |t|
    t.text     "preparation"
    t.text     "execution"
    t.string   "category"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "name"
    t.string   "body_part",      default: [], array: true
    t.hstore   "muscle_groups"
    t.string   "equipment_type", default: [], array: true
  end
Run Code Online (Sandbox Code Playgroud)

以下查询有效:

SELECT * FROM db_of_exercises WHERE ('Arms') = ANY (body_part);
Run Code Online (Sandbox Code Playgroud)

但是,此查询不会:

SELECT * FROM db_of_exercises WHERE ('Arms', 'Chest') = ANY (body_part);
Run Code Online (Sandbox Code Playgroud)

它抛出此错误:

ERROR:  operator does not exist: record = character varying
Run Code Online (Sandbox Code Playgroud)

这对我来说也不起作用:

SELECT * FROM "db_of_exercises" WHERE "body_part" IN ('Arms', 'Chest');
Run Code Online (Sandbox Code Playgroud)

这引发了这个错误:

ERROR:  array value must start with "{" or dimension information
Run Code Online (Sandbox Code Playgroud)

那么,我如何在ActiveRecord中查询具有数组数据类型的列?

我现在拥有的是:

@exercises = DbOfExercise.where(body_part: params[:body_parts])
Run Code Online (Sandbox Code Playgroud)

我希望能够查询具有多个与它们关联的body_part的记录,这是使用数组数据类型的全部要点,所以如果有人可以启发我如何做到这一点,那将是非常棒的.我没有在文档中的任何地方看到它.

后人的最终解决方案:

使用重叠运算符(&&):

SELECT * FROM db_of_exercises WHERE ARRAY['Arms', 'Chest'] && body_part;
Run Code Online (Sandbox Code Playgroud)

我收到了这个错误:

ERROR:  operator does not exist: text[] && character varying[]
Run Code Online (Sandbox Code Playgroud)

所以我将ARRAY ['Arms','Chest']类型化为varchar:

 SELECT * FROM db_of_exercises WHERE ARRAY['Arms', 'Chest']::varchar[] && body_part;
Run Code Online (Sandbox Code Playgroud)

那很有效.

Agu*_*ico 6

我不认为它与rails有关.

如果你这样做怎么办?

SELECT * FROM db_of_exercises WHERE 'Arms' = ANY (body_part) OR 'Chest' = ANY (body_part)
Run Code Online (Sandbox Code Playgroud)

我知道rails 4支持Postgresql ARRAY数据类型,但我不确定ActiveRecord是否创建了查询数据类型的新方法.也许你可以使用Array Overlap我的意思是&&运算符然后做类似的事情:

WHERE ARRAY['Arms', 'Chest'] && body_part
Run Code Online (Sandbox Code Playgroud)

或者看看这个宝石:https://github.com/dockyard/postgres_ext/blob/master/docs/querying.md

然后执行以下查询:

DBOfExercise.where.overlap(:body_part => params [:body_parts])


Cra*_*ger 6

@Aguardientico绝对正确,你想要的是数组重叠运算符&&.我正在跟进一些更多的解释,但更愿意接受这个答案,而不是这个.

匿名行(记录)

除非它出现在列表中,否则构造('item1', 'item2', ...)行构造函数IN (...).它创建了一个匿名行,PostgreSQL称之为"记录".错误:

ERROR:  operator does not exist: record = character varying
Run Code Online (Sandbox Code Playgroud)

是因为('Arms', 'Chest')它被解释为它是ROW('Arms', 'Chest'),它产生一个record值:

craig=> SELECT ('Arms', 'Chest'), ROW('Arms', 'Chest'), pg_typeof(('Arms', 'Chest'));
     row      |     row      | pg_typeof 
--------------+--------------+-----------
 (Arms,Chest) | (Arms,Chest) | record
(1 row)
Run Code Online (Sandbox Code Playgroud)

并且PostgreSQL不知道如何将它与字符串进行比较.

我真的不喜欢这种行为; 如果ROW()你想要一个匿名行,PostgreSQL要求你显式地使用构造函数,我更喜欢它.我希望这里显示的行为存在支持SET (col1,col2,col3) = (val1,val2,val3)和其他类似的操作,其中ROW(...)构造函数不会有多大意义.

但单个项目的相同之处是什么?

单个('Arms')案例工作的原因是因为除非有逗号,否则它只是一个带括号的值,其中括号是多余的,可以忽略:

craig=> SELECT ('Arms'), ROW('Arms'), pg_typeof(('Arms')), pg_typeof(ROW('Arms'));
 ?column? |  row   | pg_typeof | pg_typeof 
----------+--------+-----------+-----------
 Arms     | (Arms) | unknown   | record
(1 row)
Run Code Online (Sandbox Code Playgroud)

不要被类型吓到unknown.它只是意味着它是一个尚未应用类型的字符串文字:

craig=> SELECT pg_typeof('blah');
 pg_typeof 
-----------
 unknown
(1 row)
Run Code Online (Sandbox Code Playgroud)

将数组与标量进行比较

这个:

SELECT * FROM "db_of_exercises" WHERE "body_part" IN ('Arms', 'Chest');
Run Code Online (Sandbox Code Playgroud)

失败了:

ERROR:  array value must start with "{" or dimension information
Run Code Online (Sandbox Code Playgroud)

因为隐式铸造.body_part列的类型是text[](或者varchar[]在PostgreSQL中相同的东西).您将它与等式中的值进行比较,这些值IN是未知类型的文字.数组唯一有效的相等运算符是=另一个相同类型的数组,因此PostgreSQL认为IN子句中的值也必须是数组,text[]并尝试将它们解析为数组.

由于它们不是像数组文字那样编写的{"FirstValue","SecondValue"},因此解析失败.注意:

craig=> SELECT 'Arms'::text[];
ERROR:  array value must start with "{" or dimension information
LINE 1: SELECT 'Arms'::text[];
               ^
Run Code Online (Sandbox Code Playgroud)

看到?

一旦你看到它IN实际上只是一个简写,它就更容易理解= ANY.它与列表中的每个元素进行了相等比较IN.如果您真的想知道两个数组是否重叠,那么这不是您想要的.

这就是你想要使用数组重叠运算符的原因&&.