0

У меня есть приложение Rails с таблицей, как это:Как написать область Rails ActiveRecord, которая объединяет строки и возвращает только последнюю дату среди трех дат?

 
id | parent_id | datetime_a   | datetime_b   | datetime_c 
1 | 55  | 2013-08-03 11:00:00 | null    | null 
2 | 55  | null    | 2013-08-04 13:01:11 | null 
3 | 56  | 2013-08-02 17:33:23 | null    | null 
4 | 56  | null    | 2013-08-01 18:00:00 | null 
5 | 56  | null    | null    | 2013-07-12 07:45:00 

Я хочу написать три ActiveRecord области, которые возвращают только одну запись в parent_id и выбирает запись с последней датой-временем для конкретного столбца datetime_x и сужает до строки с заполненным столбцом datetime_x. Если конкретный parent_id имеет записи для более чем одного столбца datetime_x, он должен возвращать только строку, если datetime_x, с которым мы сужены, является последней из всех существующих. Таким образом, возможности для datetime_a вернутся:

 
id | parent_id | datetime_a   | datetime_b   | datetime_c 
3 | 56  | 2013-08-02 17:33:23 | null    | null 

Мы получаем строку для parent_id 56, потому что datetime_a является последним из трех времен даты. Мы получаем ни одна строка не возвращается для parent_id 55, потому что datetime_b для записи 2, позже, чем datetime_b для записи 1.

 
id | parent_id | datetime_a   | datetime_b   | datetime_c 
2 | 55  | null    | 2013-08-04 13:01:11 | null 

Мы получаем строку для parent_id 55, потому что запись 2 имеет последнюю DateTime из трех datetime_x колонн. Мы не получаем никаких записей parent_id 56, потому что datetime_a позже, чем datetime_b для трех записей parent_id 56.

Это то, что я до сих пор, что не работает: (при условии, что модель Foo, таблица Foo):

scope :datetime_a, ->{ select('foo.parent_id, MAX(COALESCE(datetime_a, datetime_b, datetime_c))').group('foo.parent_id').where('datetime_a IS NOT NULL') }

также попытался это:

scope :datetime_a, ->{ select('DISTINCT ON (foo.parent_id) *').where('datetime_a IS NOT NULL').order('MAX(COALESCE(datetime_a, datetime_b, datetime_c))')

Я использую Postgres, поэтому любые ответы Postgres приветствуются.

ответ

1

решаемые это следующим образом:

scope :datetime_a, ->{ find_by_sql('SELECT * FROM (SELECT DISTINCT ON (foo.parent_id) * FROM foo ORDER BY foo.parent_id, GREATEST(COALESCE(datetime_a, datetime_b, datetime_c)) DESC) AS UNIQ_PARENT WHERE UNIQ_PARENT.datetime_a IS NOT NULL') } 
+0

Это решение является проблематичным, однако, как find_by_sql возвращает массив и не ActiveRecord Collection, которые могут быть соединены. Возможно, есть способ сделать это с помощью isl_table? – Ben

+0

Я думаю, что делать это вручную с помощью SQL может быть вашим единственным вариантом, понимание ActiveRecord о нетривиальном SQL (например, производные таблицы, функции окна, CTEs ...) крайне ограничено. –

Смежные вопросы