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)
那很有效.
我不认为它与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])
@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.如果您真的想知道两个数组是否重叠,那么这不是您想要的.
这就是你想要使用数组重叠运算符的原因&&.