在ActiveRecord中的WHERE语句中使用array_length

时间:2016-10-20 20:30:12

标签: sql ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord

我更喜欢使用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)不返回任何内容。

1 个答案:

答案 0 :(得分:1)

我认为问题的根源是当数组为空时array_lengthnull

=> 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>

我想到了两个简单的解决方案:

  1. 您可以在范围内明确处理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
    
  2. 对查询进行coalesce调用,将NULL转换为零,让数据库担心:

    def self.of_order(num)
      where('coalesce(array_length(sequence, 1), 0) = ?', num)
    end