2015-05-16 12 views
5

Hinweis zu kombinieren: Ich habe die neueste Version von Postgres bin mit (9,4)Wie DISTINCT und ORDER BY in array_agg von jsonb Werte in PostgresSQL

ich eine Abfrage zu schreiben, ich versuche, die eine einfache 2 Tabellen beitritt, und gruppiert nach dem Primärschlüssel der ersten Tabelle und führt eine array_agg mehrerer Felder in der zweiten Tabelle durch, die ich als Objekt zurückgeben möchte. Das Array muss nach einer Kombination von 2 Feldern in den JSON-Objekten sortiert werden und auch unifiziert sein.

Bisher habe ich mit dem folgenden kommen:

SELECT 
    zoo.id, 
    ARRAY_AGG(
    DISTINCT ROW_TO_JSON(( 
     SELECT x 
     FROM ( 
     SELECT animals.type, animals.name 
    ) x 
    ))::JSONB 
    -- ORDER BY animals.type, animals.name 
) 
    FROM zoo 
    JOIN animals ON animals.zooId = zoo.id 
    GROUP BY zoo.id; 

Dies ergibt eine Zeile für jeden Zoo, mit einem Aggregate Array von jsonb Objekten, eines für jedes Tier, eindeutig.

Allerdings kann ich nicht herausfinden, wie dies auch durch die Parameter im auskommentierten Teil des Codes zu sortieren ist.

Wenn ich das distinct, kann ich ORDER BY ursprüngliche Felder, die funktioniert gut, aber dann habe ich Duplikate.

+0

Können Sie einige Beispieldaten und die gewünschte Ausgabe bereitstellen? – Eggplant

Antwort

2

Wenn Sie row_to_json() verwenden, verlieren Sie die Spaltennamen, es sei denn, Sie geben eine getippte Zeile ein. Wenn Sie „manuell“ bauen die jsonb Objekt mit json_build_object() mit expliziten Namen dann bekommt man sie zurück:

SELECT zoo.id, array_agg(za.jb) AS animals 
FROM zoo 
JOIN (
    SELECT DISTINCT ON (zooId, "type", "name") 
    zooId, json_build_object('animal_type', "type", 'animal_name', "name")::jsonb AS jb 
    FROM animals 
    ORDER BY zooId, jb->>'animal_type', jb->>'animal_name' 
    -- ORDER BY zooId, "type", "name" is far more efficient 
) AS za ON za.zooId = zoo.id 
GROUP BY zoo.id; 

Sie die Elemente eines jsonb Objekt ORDER BY kann, wie oben gezeigt, aber (soweit ich weiß) Sie kann DISTINCT auf einem jsonb Objekt nicht verwenden. In Ihrem Fall wäre das sowieso ziemlich ineffizient (zuerst werden alle jsonb Objekte erstellt, dann werden Duplikate verworfen) und auf der aggregierten Ebene ist es mit Standard-SQL schlicht unmöglich. Sie können jedoch das gleiche Ergebnis erzielen, indem Sie vor dem Erstellen des jsonb-Objekts die DISTINCT-Klausel anwenden.

Vermeiden Sie auch die Verwendung von SQL key words wie "type" und Standarddatentypen wie "name" als Spaltennamen. Beide sind nicht reservierte Schlüsselwörter, so dass Sie sie in ihren richtigen Kontexten verwenden können, aber Ihre Befehle könnten praktisch verwirrend werden. Sie könnten zum Beispiel ein Schema haben, mit einer Tabelle, eine Spalte in der Tabelle, und ein Datentyp jeden „Typ“ und dann könnte man diese:

SELECT type::type FROM type.type WHERE type = something; 

Während PostgreSQL dies akzeptiert gnädig, Es ist im besten Fall einfach verwirrend und anfällig für Fehler in allen Arten von komplexeren Situationen. Sie können einen langen Weg gehen, indem Sie alle Schlüsselwörter doppelt zitieren, aber sie werden am besten nur als Bezeichner vermieden.

+0

Da die Abfrage, die ich zur Verfügung gestellt habe, tatsächlich eine Teilmenge einer größeren Abfrage ist (die ich zur Vereinfachung der Fragestellung reduziert habe), habe ich vergessen, dass es einen WHERE-Parameter der Zootabelle gibt. Wie bei der von Ihnen bereitgestellten Abfrage würde dies das Problem lösen, aber es beantwortet immer noch nicht die primäre Frage, die ich hatte, ob es möglich ist, DISTINCT und ORDER BY in einem Aggregat von erzeugten JSONB-Werten zu kombinieren (eins von beiden) scheint gut zu funktionieren). Können Sie bitte auch die Verwendung von "name" und "type" erläutern? Ist das ein Problem in Postgres oder nur allgemein? – Philberg