PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL 9.3:Dynamiczna tabela przestawna

Możesz to zrobić za pomocą crosstab() z dodatkowego modułu tablefunc:

SELECT b
     , COALESCE(a1, 0) AS "A1"
     , COALESCE(a2, 0) AS "A2"
     , COALESCE(a3, 0) AS "A3"
     , ... -- all the way up to "A30"
FROM   crosstab(
         'SELECT colb, cola, 1 AS val FROM matrix
          ORDER  BY 1,2'
        , $$SELECT 'A'::text || g FROM generate_series(1,30) g$$
       ) AS t (b text
             , a1  int, a2  int, a3  int, a4  int, a5  int, a6  int
             , a7  int, a8  int, a9  int, a10 int, a11 int, a12 int
             , a13 int, a14 int, a15 int, a16 int, a17 int, a18 int
             , a19 int, a20 int, a21 int, a22 int, a23 int, a24 int
             , a25 int, a26 int, a27 int, a28 int, a29 int, a30 int);

Jeśli NULL zamiast 0 działa też, może to być po prostu SELECT * w zewnętrznym zapytaniu.
Szczegółowe wyjaśnienie:

  • Kwerendy PostgreSQL Crosstab

Szczególna „trudność” tutaj:brak rzeczywistej „wartości”. Dodaj więc 1 AS val jako ostatnia kolumna.

Nieznana liczba kategorii

Całkowicie dynamiczne zapytanie (z nieznanym typem wyniku) nie jest możliwe w pojedynczym zapytaniu. Potrzebujesz dwóch zapytania. Najpierw zbuduj dynamicznie instrukcję taką jak powyżej, a następnie ją wykonaj. Szczegóły:

  • Wybór wielu wartości max() za pomocą jednej instrukcji SQL

  • PostgreSQL konwertuje kolumny na wiersze? Transponować?

  • Dynamicznie generuj kolumny dla tabeli krzyżowej w PostgreSQL

  • Dynamiczna alternatywa dla pivota z CASE i GROUP BY

Zbyt wiele kategorii

Jeśli przekroczysz maksymalną liczbę kolumn (1600), klasyczna tabela przestawna jest niemożliwa, ponieważ wynik nie może być reprezentowany przez pojedyncze kolumny. (Ponadto ludzkie oczy prawie nie byłyby w stanie odczytać tabeli z tyloma kolumnami)

Tablice lub typy dokumentów, takie jak hstore lub jsonb są alternatywą. Oto rozwiązanie z tablicami:

SELECT colb, array_agg(cola) AS colas
FROM  (
   SELECT colb, right(colb, -1)::int AS sortb
        , CASE WHEN m.cola IS NULL THEN 0 ELSE 1 END AS cola
   FROM        (SELECT DISTINCT colb FROM matrix) b
   CROSS  JOIN (SELECT DISTINCT cola FROM matrix) a
   LEFT   JOIN matrix m USING (colb, cola)
   ORDER  BY sortb, right(cola, -1)::int 
   ) sub
GROUP  BY 1, sortb
ORDER  BY sortb;
  • Zbuduj pełną siatkę wartości za pomocą:

                (SELECT DISTINCT colb FROM matrix) b
    CROSS  JOIN (SELECT DISTINCT cola FROM matrix) a
    
  • LEFT JOIN istniejące kombinacje, uporządkuj według numerycznej części nazwy i agreguj w tablice.

    • right(colb, -1)::int przycina wiodący znak z „A3” i przekształca cyfry na liczby całkowite, dzięki czemu uzyskujemy właściwą kolejność sortowania.

Macierz podstawowa

Jeśli chcesz tylko tabelę 0 1 gdzie x = y , można to zrobić taniej:

SELECT x, array_agg((x = y)::int) AS y_arr
FROM   generate_series(1,10) x
     , generate_series(1,10) y
GROUP  BY 1
ORDER  BY 1;

Skrzypce SQL oparty na tym, który podałeś w komentarzach.

Zauważ, że sqlfiddle.com ma obecnie błąd, który zabija wyświetlanie wartości tablicy. Więc przesyłam do text tam, aby to obejść.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak ustawić limit czasu połączenia w SQLAlchemy?

  2. PostgreSQL zwraca zestaw wyników jako tablicę JSON?

  3. PostgreSQL:Utwórz indeks dla kolumny logicznej

  4. Nie można uruchomić Postgresa

  5. Przyszłość Postgres-XL