Сложные рельсы найти заказ - PullRequest
0 голосов
/ 03 августа 2010

Я пытаюсь найти, какие заказы получаются по имени их дома, а затем по фамилии клиента.

Customer.find(:all, 
    :conditions =>['customers.id IN (?)', intersection], 
    :joins => 'JOIN histories ON histories.customer_id = customers.id
     JOIN houses ON histories.house_id = houses.id',
    :order => "houses.name ASC, customers.last_name ASC",
    :select => "customers.*, histories.job_title, houses.name"
)

Моя проблема в том, что это вернет все истории, связанные с каждым клиентом.

если я добавлю AND history..finish_date = NULL Это предотвратит возвращение каждой истории для выбранного клиента, но также предотвратит возвращение клиентов на перекрестке, у которых нет истории или задан параметр finish_date.

В основном мне нужно, чтобы каждый покупатель на перекрестке возвращался один раз с указанием текущего имени дома (если он есть), а затем заказывал по имени дома, а затем по фамилии.

Так есть ли способ сделать это?

Вот пример

клиент

id  last_name
1     franks
2     doors
3     greens

история

id    finish_date      house_id     customer_id
1        NULL             1             1
2        NULL             2             2
3        11/03/10         2             1
4        22/04/09         1             2

NULL = текущий дом

дома

id name
1    a
2    b

Результаты

пересечение = 1,2,3

last_name       house     
franks            a
doors             b
greens            NULL

Спасибо

Ответы [ 2 ]

0 голосов
/ 04 августа 2010

Я думаю, вам нужно использовать внешние соединения.

Например, это должно работать:

Customer.find(:all, 
  :conditions =>['customers.id IN (?) and histories.finish_date is null', intersection], 
  :joins => 'LEFT OUTER JOIN histories ON histories.customer_id = customers.id
    LEFT OUTER JOIN houses ON histories.house_id = houses.id',
  :order => "houses.name ASC, customers.last_name ASC",
  :select => "customers.*, histories.job_title, houses.name"
)

Если у вас есть связь между клиентом и историей, а также между историей и домом, вы можете сделать :include => [:histories => :house] вместо опции :joins.

Единственное другое, что клиенты без дома появятся первыми в списке из-за того, что NULL находится в заказе раньше, чем значение, отличное от NULL. Возможно, вы захотите попробовать вариант заказа, как это:

:order => 'isnull(houses.name), houses.name, customers.last_name'

чтобы достичь того, что вы указали.

0 голосов
/ 03 августа 2010

IMO, проще сделать логику сортировки в Rails вместо базы данных:

customers = Customer.find(:all, :conditions => { :id  => intersection }, :include => [ { :histories => :houses } ])

customers.sort_by { |c| c.last_name }
customers.sort_by do |c|
  current_house = c.histories.find_by_finish_date(nil) # Returns nil if no matching record found
  if current_house
    current_house.name
  else
    ''
  end
end

Пояснения

  • : условия могут принимать хеш {: column_name => array}, который переводится в ваше IN, где условие
  • : включить предварительную загрузку ( готовая загрузка ) таблицы, если существуют соответствующие ассоциации. Другими словами:: joins создает INNER JOINs, а: include создает LEFT JOINs . Здесь мы оставим объединенные истории и снова оставим объединенные дома. Вы можете опустить это: включить тег, в этом случае rails выполняет новый запрос каждый раз, когда вы обращаетесь к свойству истории или домов.
  • sort_by позволяет определить пользовательские критерии сортировки.
  • find_by_finish_date - один из магических методов рельсов; это эквивалентно h.find(:conditions => {:finish_date => nil })
  • Как вывести: просто выведите их все на ваше усмотрение. Если у него нет историй, то customer.histories - это пустой массив.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...