2015-05-16 37 views
5

Uwaga: Używam najnowszej wersji PostgreSQL (9.4)Jak łączyć odrębne i ORDER BY w array_agg wartości jsonb w PostgresSQL

próbuję napisać zapytanie, które wykonuje proste przyłączenia z 2 tabel, i grupuje kluczem podstawowym pierwszej tabeli, i wykonuje tablicę_agg wielu pól w drugiej tabeli, które chcę zwrócić jako obiekt. Tablica musi być posortowana według kombinacji 2 pól w obiektach json, a także unikatowa.

Do tej pory mają pochodzić z następujących czynności:

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; 

Wynika to w jednym wierszu dla każdego zoo, o łącznej tablicy jsonb obiektów, po jednej dla każdego zwierzęcia, jednoznacznie.

Nie mogę jednak wymyślić sposobu sortowania tego również według parametrów w skomentowanej części kodu.

Jeśli wybiorę wyraźne, mogę ZAMÓWIĆ według oryginalnych pól, co działa świetnie, ale potem mam duplikaty.

+0

Czy możesz podać przykładowe dane i pożądane wyniki? – Eggplant

Odpowiedz

2

Jeśli użyjesz row_to_json(), utracisz nazwy kolumn, chyba że wpiszesz wpisany wiersz. Jeśli „ręcznie” zbudować obiekt jsonb z json_build_object() używając jednoznacznych nazw następnie dostać je z powrotem:

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; 

Można ORDER BY te elementy jsonb obiektu, jak wykazano powyżej, ale (o ile wiem), które nie można użyć obiektu DISTINCT na obiekcie jsonb. W twoim przypadku byłoby to raczej nieefektywne w każdym razie (najpierw budowanie wszystkich obiektów jsonb, a następnie wyrzucanie duplikatów) i na poziomie zagregowanym jest to niemożliwe przy standardowym SQL. Możesz osiągnąć ten sam wynik, stosując klauzulę DISTINCT przed zbudowaniem obiektu jsonb.

Należy również unikać używania SQL key words takich jak "typ" i standardowych typów danych, takich jak "nazwa", jak nazwy kolumn. Oba są niezarezerwowanymi słowami kluczowymi, dzięki czemu można je używać w ich odpowiednich kontekstach, ale praktycznie mówiąc, polecenia użytkownika mogą być naprawdę mylące. Można na przykład mieć schemat, ze stołem, kolumny w tej tabeli, a typ danych każdego zwanego „typ”, a następnie można uzyskać to:

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

Chociaż PostgreSQL będzie łaskawie przyjąć to, w najlepszym wypadku jest to mylące i podatne na błędy we wszystkich bardziej złożonych sytuacjach. Możesz uzyskać długą drogę poprzez podwójne cytowanie dowolnych słów kluczowych, ale najlepiej unikać takich identyfikatorów.

+0

Ponieważ podane przeze mnie zapytanie jest w rzeczywistości podzbiorem większego zapytania (które zredukowaliśmy dla uproszczenia w zadawaniu pytania), zapomniałem, że istnieje WHERE na parametrach tabeli zoo. Jeśli chodzi o zapytanie, które podałeś, to rozwiązałoby to problem, ale nadal nie odpowiada na podstawowe pytanie, które miałem, czyli czy możliwe jest łączenie DISTINCT i ORDER BY w agregacie utworzonych wartości JSONB (jeden z nich wydaje się działać świetnie). Czy mógłbyś także rozwinąć kwestię używania "nazwy" i "typu"? Czy jest to problem w postgresie, czy ogólnie? – Philberg