Ich habe einige meiner MySQL-Abfragen nach PostgreSQL migriert, um Heroku zu verwenden. Die meisten meiner Abfragen funktionieren einwandfrei, aber ich habe immer wieder einen ähnlichen wiederkehrenden Fehler, wenn ich group by verwende:
FEHLER: Die Spalte "XYZ" muss in der GROUP BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden
Könnte mir jemand sagen, was ich falsch mache?
MySQL, das zu 100% funktioniert:
SELECT `availables`.*
FROM `availables`
INNER JOIN `rooms` ON `rooms`.id = `availables`.room_id
WHERE (rooms.hotel_id = 5056 AND availables.bookdate BETWEEN '2009-11-22' AND '2009-11-24')
GROUP BY availables.bookdate
ORDER BY availables.updated_at
PostgreSQL-Fehler:
ActiveRecord :: StatementInvalid: PGError: ERROR: Die Spalte "Availables.id" muss in der GROUP BY-Klausel enthalten sein oder in einer Aggregatfunktion verwendet werden:
SELECT "Available". * FROM "Available" INNER JOIN "Zimmer" ON "Zimmer". id = "available" .room_id WHERE (rooms.hotel_id = 5056 AND available.bookdate ZWISCHEN E'2009-10-21 'UND E'2009-10-23') GROUP BY available.bookdate ORDER BY available.updated_at
Ruby-Code, der das SQL generiert:
expiration = Available.find(:all,
:joins => [ :room ],
:conditions => [ "rooms.hotel_id = ? AND availables.bookdate BETWEEN ? AND ?", hostel_id, date.to_s, (date+days-1).to_s ],
:group => 'availables.bookdate',
:order => 'availables.updated_at')
Erwartete Ausgabe (von der funktionierenden MySQL-Abfrage):
+ ----- + ------- + ------- + ------------ + --------- + ---- ----------- + --------------- + | id | Preis | Flecken | Buchdatum | room_id | created_at | aktualisierte_at | + ----- + ------- + ------- + ------------ + --------- + ---- ----------- + --------------- + | 414 | 38,0 | 1 | 2009-11-22 | 1762 | 20.11.2009 ... | 20.11.2009 ... | | 415 | 38,0 | 1 | 2009-11-23 | 1762 | 20.11.2009 ... | 20.11.2009 ... | | 416 | 38,0 | 2 | 24.11.2009 | 1762 | 20.11.2009 ... | 20.11.2009 ... | + ----- + ------- + ------- + ------------ + --------- + ---- ----------- + --------------- + 3 Reihen im Set
quelle
DISTINCT
ist langsamer alsGROUP BY
. Sie sollten also vorsichtig sein und eineGROUP BY
Lösung bevorzugen , wenn dies möglich ist.Antworten:
MySQLs völlig nicht standardkonforme
GROUP BY
können von Postgres emuliert werdenDISTINCT ON
. Bedenken Sie:MySQL:
SELECT a,b,c,d,e FROM table GROUP BY a
Dies liefert 1 Zeile pro Wert von
a
(welche, die Sie nicht wirklich kennen). Nun, eigentlich können Sie raten, weil MySQL nichts über Hash-Aggregate weiß, also wird es wahrscheinlich eine Sortierung verwenden ... aber es wird nur weiter sortierena
, so dass die Reihenfolge der Zeilen zufällig sein könnte. Es sei denn, es wird ein mehrspaltiger Index anstelle der Sortierung verwendet. Jedenfalls wird es von der Abfrage nicht angegeben.Postgres:
SELECT DISTINCT ON (a) a,b,c,d,e FROM table ORDER BY a,b,c
Dies liefert 1 Zeile pro Wert von
a
. Diese Zeile ist die erste in der Sortierung gemäß der inORDER BY
der Abfrage angegebenen. Einfach.Beachten Sie, dass es sich hier nicht um ein Aggregat handelt, das ich berechne. Also
GROUP BY
macht eigentlich eigentlich keinen Sinn.DISTINCT ON
macht viel mehr Sinn.Rails ist mit MySQL verheiratet, daher wundert es mich nicht, dass SQL generiert wird, das in Postgres nicht funktioniert.
quelle
group by
Klausel ist.PostgreSQL ist SQL-kompatibler als MySQL. Alle Felder - außer dem berechneten Feld mit Aggregationsfunktion - in der Ausgabe müssen in der GROUP BY-Klausel vorhanden sein.
quelle
GROUP BY von MySQL kann ohne Aggregatfunktion verwendet werden (was dem SQL-Standard widerspricht) und gibt die erste Zeile in der Gruppe zurück (ich weiß nicht anhand welcher Kriterien), während PostgreSQL eine Aggregatfunktion haben muss (MAX, SUM usw.) in der Spalte, in der die GROUP BY-Klausel ausgegeben wird.
quelle
Richtig, die Lösung, um dies zu beheben, besteht darin, Folgendes auszuwählen und auszuwählen, und wählen Sie jedes Feld aus, mit dem Sie das resultierende Objekt dekorieren möchten, und gruppieren Sie es nach diesen.
Böse - aber es ist, wie Gruppieren nach funktionieren sollte , im Gegensatz dazu, wie MySQL damit arbeitet, indem Sie erraten, was Sie meinen, wenn Sie keine Felder in Ihrer Gruppe durchkleben.
quelle
Wenn ich es richtig, in PostgreSQL erinnern müssen Sie jede Spalte fügen Sie aus der Tabelle zu holen , wo die GROUP BY - Klausel gilt auf der GROUP BY - Klausel.
quelle
Nicht die schönste Lösung, aber das Ändern des Gruppenparameters zur Ausgabe jeder Spalte im Modell funktioniert in PostgreSQL:
expiration = Available.find(:all, :joins => [ :room ], :conditions => [ "rooms.hotel_id = ? AND availables.bookdate BETWEEN ? AND ?", hostel_id, date.to_s, (date+days-1).to_s ], :group => Available.column_names.collect{|col| "availables.#{col}"}, :order => 'availables.updated_at')
quelle
Laut MySQLs "Debuking GROUP BY Myths" http://dev.mysql.com/tech-resources/articles/debunking-group-by-myths.html . SQL (Version 2003 des Standards) erfordert nicht, dass Spalten, auf die in der SELECT-Liste einer Abfrage verwiesen wird, auch in der GROUP BY-Klausel angezeigt werden.
quelle
GROUP BY
. Die Fähigkeit von MySQL zu verweisen alle nicht gruppierten Spalte ist vollständig nicht-Standard und ermöglicht es Benutzern , unlogisch und unzuverlässig Abfragen zu schreiben.GROUP BY
Ignorieren von MySQL Beschränkungen auferlegen .Verwenden Sie für andere, die nach einer Möglichkeit suchen, nach einem beliebigen Feld, einschließlich eines verbundenen Felds, in postgresql zu ordnen, eine Unterabfrage:
SELECT * FROM( SELECT DISTINCT ON(availables.bookdate) `availables`.* FROM `availables` INNER JOIN `rooms` ON `rooms`.id = `availables`.room_id WHERE (rooms.hotel_id = 5056 AND availables.bookdate BETWEEN '2009-11-22' AND '2009-11-24') ) AS distinct_selected ORDER BY availables.updated_at or arel: subquery = SomeRecord.select("distinct on(xx.id) xx.*, jointable.order_field") .where("").joins(") result = SomeRecord.select("*").from("(#{subquery.to_sql}) AS distinct_selected").order(" xx.order_field ASC, jointable.order_field ASC")
quelle
Ich denke, dass .uniq [1] Ihr Problem lösen wird.
Schauen Sie sich http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields an
quelle