#sql #ruby-on-rails #postgresql #ruby-on-rails-4 #rails-activerecord
#sql #ruby-on-rails #postgresql #ruby-on-rails-4 #rails-activerecord
Вопрос:
Мне удобнее использовать activerecord в отличие от ванильного SQL, поэтому у меня возникли небольшие проблемы.
У меня есть таблица связей со свойством, называемым sequence, которое имеет тип array. Массив либо пуст, либо содержит серию чисел.
Чего я пытаюсь достичь, так это написать область AR, которая позволяет мне возвращать только записи, размер массива последовательности которых равен num
. Я представляю, что это выглядит примерно так:
def self.of_order(num)
where("array_length(sequence, 1) = ?", num)
end
Если бы это было доступно в active record, я бы представил, что это выглядит как:
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)
чтобы вернуть первую запись,
Relationship.of_order(3)
чтобы вернуть вторую запись,
и Relationship.of_order(2)
для возврата none.
Комментарии:
1. покажите более подробную информацию о вашей модели и миграциях, а также некоторые примеры данных…
2. добавлен @johnnynemonic
3. @muistoosh, который выдает
SELECT "relationships".* FROM "relationships" WHERE (array_length(sequence, 1) = 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
внутри базы данных, а это никогда не бывает правдой, поэтому вы не найдете свои пустые массивы.
На ум приходят два простых решения:
-
Вы можете явно обработать
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
вызов в запросе для преобразования нулевых значений в нули и предоставьте базе данных беспокоиться об этом:def self.of_order(num) where('coalesce(array_length(sequence, 1), 0) = ?', num) end
Комментарии:
1. Герой! избавило меня от головной боли