我更喜欢使用activerecord而不是vanilla SQL,所以我有点麻烦。
我有一个Relationships表,其中包含一个名为sequence的属性,类型为array。该数组为空或包含一系列数字。
我想要实现的是编写AR范围,允许我只返回其序列数组大小等于num
的记录。我想它看起来像这样:
def self.of_order(num)
where("array_length(sequence, 1) = ?", num)
end
如果它在活动记录中可用,我会想象它看起来像:
def self.of_order(num)
where(sequence.size == num)
end
编辑: 以下是迁移的内容:
class CreateRelationships < ActiveRecord::Migration
def change
create_table :relationships do |t|
t.integer :root_id
t.integer :destination_id
t.boolean :first_order?
t.text :sequence, array: true, default: []
t.timestamps null: false
end
end
end
示例数据:
[
[ 0] #<Relationship:0x007f8d5a5c82c8> {
:id => 73,
:root_id => 51,
:target_id => 52,
:first_order? => true,
:sequence => [],
:created_at => Thu, 20 Oct 2016 19:05:22 UTC +00:00,
:updated_at => Thu, 20 Oct 2016 19:05:22 UTC +00:00,
:primitive_type => "spouse"
},
[ 1] #<Relationship:0x007f8d5a5c8188> {
:id => 74,
:root_id => 52,
:target_id => 51,
:first_order? => true,
:sequence => [22,43,90],
:created_at => Thu, 20 Oct 2016 19:05:22 UTC +00:00,
:updated_at => Thu, 20 Oct 2016 19:05:22 UTC +00:00,
:primitive_type => "spouse"
}
]
我希望Relationship.all
返回两条记录,
Relationship.of_order(0)
返回第1条记录,
Relationship.of_order(3)
返回第2条记录,
并且Relationship.of_order(2)
不返回任何内容。
答案 0 :(得分:1)
我认为问题的根源是当数组为空时array_length
为null
:
=> select array_length(array[]::text[], 1);
array_length
--------------
(1 row)
=> select coalesce(array_length(array[]::text[], 1), 0);
coalesce
----------
0
(1 row)
这并没有完全清楚地记录下来,所以如果你错过了它就不会感觉不好。
所以给出:
def self.of_order(num)
where("array_length(sequence, 1) = ?", num)
end
Relationship.of_order(6)
可以正常工作,但Relationship.of_order(0)
最终会尝试在数据库中执行null = 0
,但这是不正确的,因此您无法找到空数组。< / p>
我想到了两个简单的解决方案:
您可以在范围内明确处理of_order(0)
案例:
def self.of_order(num)
if(num == 0)
where('array_length(sequence, 1) is null')
else
where('array_length(sequence, 1) = ?', num)
end
end
对查询进行coalesce
调用,将NULL转换为零,让数据库担心:
def self.of_order(num)
where('coalesce(array_length(sequence, 1), 0) = ?', num)
end