2016-11-01 4 views
2

Ich habe ein Rails 4.2.5.x-Projekt mit PostGres. Ich habe eine Tabelle mit einer ähnlichen Struktur wie folgt aus:So erhalten Sie die neuesten Zeilen in einer Gruppe

id, contact_id, date,  domain, f1, f2, f3, etc 
1, ABC,  01-01-16, abc.com, 1, 2, 3, ... 
2, ABC,  01-01-15, abc.com, 1, 2, 3, ... 
3, ABC,  01-01-14, abc.com, 1, 2, 3, ... 
4, DEF,  01-01-15, abc.com, 1, 2, 3, ... 
5, DEF,  01-01-14, abc.com, 1, 2, 3, ... 
6, GHI,  01-11-16, abc.com, 1, 2, 3, ... 
7, GHI,  01-01-16, abc.com, 1, 2, 3, ... 
8, GHI,  01-01-15, abc.com, 1, 2, 3, ... 
9, GHI,  01-01-14, abc.com, 1, 2, 3, ... 
... 
... 
99, ZZZ,  01-01-16, xyz.com, 1, 2, 3, ... 

ich abfragen müssen, um finden:

  • Die jüngsten Reihen von date
  • von Domain
  • für eine bestimmte contact_id gefiltert (gruppiert nach?)
  • Zeilenbegrenztes Ergebnis. In diesem Beispiel füge ich diese Komplikation nicht hinzu, aber das muss berücksichtigt werden. Wenn es 50 verschiedene Kontakte gibt, interessiert mich nur die Top 3 nach Datum.
  • ID ist der Primärschlüssel.
  • gibt es Indizes für die anderen Spalten
  • die fX Spalten zeigen andere Daten im Modell an, das benötigt wird (z. B. Kontakt-E-Mail).

In MySQL, dies wäre eine einfache SELECT * FROM table WHERE domain='abc.com' GROUP BY contact_id ORDER BY date DESC jedoch PostGres beklagt, in diesem Fall, dass:

ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "table.id" must appear in the GROUP BY clause or be used in an aggregate function

Ich erwarte, dass 3 Reihen zurück zu erhalten; 1, 4 und 6. Im Idealfall möchte ich die vollständigen Zeilen in einer einzigen Abfrage zurückgeben ... aber ich akzeptiere, dass ich möglicherweise eine Abfrage durchführen muss, um die IDs zuerst zu erhalten, dann eine weitere auf find die Elemente, die ich möchte .

Dies ist die nächste, die ich bekommen haben:

ExampleContacts 
    .select(:contact_id, 'max(date) AS max_date') 
    .where(domain: 'abc.com') 
    .group(:contact_id) 
    .order('max_date desc') 
    .limit(3) 

aber ... das gibt die contact_id, nicht die id. Ich kann die ID für die Zeile nicht hinzufügen.

EDIT:

Im Grunde brauche ich den Primärschlüssel zurück für die Zeile zu erhalten, die durch ein anderes Feld auf dem Nicht-Primärschlüssel und sortierte gruppiert ist.

+0

DOH;) 4.2.5.x;) * mich Bearbeitungen * – Nick

Antwort

1

Wenn Sie die Zeilen möchten, brauchen Sie keine Gruppierung. Es ist einfach Contact.select('DISTINCT ON (contact_id)').where(domain: 'abc.com').order(date: :desc).limit(3)

+0

ich auf die gerade gestolpert Gleiche ... Danke! – Nick

+1

Großartig! Froh, dass es für dich arbeitet. Könnten Sie die Antwort dann akzeptieren? Vielen Dank. –

+0

Ich habe die Lösung, die ich verwendet habe basierend auf dieser Antwort veröffentlicht: http://StackOverflow.com/A/40367494/224707 – Nick

0

Gerade @ murad-Yusufov die akzeptierte Antwort zu klären, landete ich tun dies:

subquery = ExampleContacts.select('DISTINCT ON (contact_id) *') 
          .where(domain: 'abc.com') 
          .order(contact_id) 
          .order(date: :desc) 

ExampleContacts.from("(#{subquery.to_sql}) example_contacts") 
       .order(date: :desc) 
Verwandte Themen