2011-05-05 3 views
20

У вас есть таблица User, UserBadge и Badge. Они связаны через has_many через. Пользователь может иметь несколько одинаковых значков, но я хочу запросить уникальный список.Rails 3 DISTINCT QUERY

@user.badges.select("DISTINCT id").order("created_at DESC") 

Это бросает ошибку:

SQLite3::SQLException: near "DISTINCT": syntax error: 

Что бы правильный синтаксис?

EDIT: ДОБАВЛЕНО ВЕСЬ ОШИБКА

SQLite3::SQLException: near "DISTINCT": syntax error: SELECT "badges".*, DISTINCT badges.id FROM "badges" INNER JOIN "userbadges" ON "badges".id = "userbadges".badges_id WHERE (("userbadges".user_id = 1)) 

Может быть запятая между выбрать и различны?

+0

вы должны включить весь текст ошибки в свой вопрос, там что-то странное происходит. – klochner

+0

Что такое сгенерированный SQL? – Vadim

+1

Запятая между выбором и отдельными является проблемой. У меня такая же проблема, когда я пытаюсь выбрать выделение с помощью соединения. Я думаю, проблема в том, что Rails добавляет первое предложение select всякий раз, когда у вас есть соединение, так что он только вытягивает правильные поля, тогда ваш вызов 'select' добавляет другой, и они объединены запятыми. Мне кажется, как ошибка в Rails. – David

ответ

3

Попробуйте

@user.badges.select("DISTINCT(badges.id)").order("badges.created_at DESC") 
+0

Нет, все еще выдает ошибку – John

21

Может попробовать использовать группу

@user.badges.group(:id) 
+0

Спасибо. Отлично работал для моего варианта использования (который в основном такой же, как у OP) – mindeavor

+6

Упс никогда не будет. Это не работает с PostgreSQL. – mindeavor

+0

Yep .. никакой радости здесь тоже .. – baash05

27

DISTINCT должно быть прямо после того, как SELECT, т.е.

SELECT DISTINCT(badges.id), "badges".* FROM "badges" INNER JOIN "userbadges" ON "badges".id = "userbadges".badges_id WHERE (("userbadges".user_id = 1)) 

Try:

@user.select("DISTINCT(badges.id), badges.*").badges.order("badges.created_at DESC") 

PostgreSQL требует у вас есть оператор порядка для отдельного поля:

@user.select("DISTINCT(badges.id), badges.*").badges.order("badges.id").order("badges.created_at DESC") 
+3

Спасибо за метод PostreSQL этого. :) –

+0

Самая важная часть здесь - это способ добавления значков. * Или в основном * в любой запрос выбора, который вы хотите заказать на элементах позже. –

7

Set

:uniq => true 

на ассоциации. Или создайте отдельную ассоциацию только для уникальных значков пользователя.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

Что-то вроде

Class User < ActiveRecord::Base 
    has_many :user_badges 
    has_many :badges, :through => :user_badges 
    has_many :unique_badges, :through => :user_badges, :source => :badges, :uniq => true 
    #untested 
end 
+2

Почему у этого нет больше упреков?Все остальные ответы кажутся обратными и сложными, и это прекрасно работает. – Armand

+1

@Alison, создавая еще одну ассоциацию, очень тяжело и плохое решение. – sidney

+0

@sidney, создающее еще одну ассоциацию, не * действительно *, что тяжело, и я бы сказал, что это не плохое решение. Если это имеет смысл для вашего случая использования, я думаю, что это действительный подход. –

3

У меня была аналогичная проблема, с использованием PostgreSQL тоже.

Мой код выглядит следующим образом:

User.find(2).devices.group('token') 

который вызвал ошибку:

Device Load (0.8ms) SELECT "devices".* FROM "devices" WHERE "devices"."user_id" = 2 GROUP BY token 
ActiveRecord::StatementInvalid: PG::Error: ERROR: column "devices.id" must appear in the GROUP BY clause or be used in an aggregate function 

Решение:

Изменение этой строки на:

User.find(2).devices.select('distinct token') 

работал отлично:

Device Load (1.3ms) SELECT distinct token FROM "devices" WHERE "devices"."user_id" = 2 
=> [#<Device token: "example">, #<Device token: "example1">, #<Device token: "example2">, #<Device token: "example3">, #<Device token: "example4">, #<Device token: "example4">] 

Update:

К сожалению, я не читал оригинальный вопрос тщательно и фактически ответил на другую должность в потоке, жалуясь метода #group не работает с PostgreSQL. Это все равно ценный ответ, поэтому я оставлю его.

1
@user.badges.select("id").order("created_at DESC").uniq 

Эта работа для меня.

+0

Вам действительно нужен звонок .uniq? Разве это не было бы лишним? –

+0

О, да извините, это просто .uniq –

+2

Подумайте, объясните, что делает ваш код! – Victor

1

Есть по крайней мере три способа получить уникальный список значков от пользователя:

  1. @user.badges.group(:id)
  2. @user.badges.select("DISTINCT badges.*")
  3. Или добавить :uniq => true в has_many :badges, :through линии

Конечно , вы также можете связать запрос order("badges.created_at DESC").