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

Wybierz dynamiczny zestaw kolumn z tabeli i uzyskaj sumę dla każdej z nich

To zapytanie tworzy pełną instrukcję DML, której szukasz:

WITH x AS (
   SELECT 'public'::text     AS _schema  -- provide schema name ..
         ,'somereport'::text AS _tbl     -- .. and table name once
   )
SELECT 'SELECT ' || string_agg('sum(' || quote_ident(column_name)
                 || ') AS sum_' || quote_ident(column_name), ', ')
       || E'\nFROM   ' || quote_ident(x._schema) || '.' || quote_ident(x._tbl)
FROM   x, information_schema.columns
WHERE  table_schema = _schema
AND    table_name = _tbl
AND    data_type = 'integer'
GROUP  BY x._schema, x._tbl;

Możesz wykonać je osobno lub zapakować to zapytanie w funkcję plpgsql i uruchomić zapytanie automatycznie za pomocą EXECUTE :

Pełna automatyzacja

Testowane z PostgreSQL 9.1.4

CREATE OR REPLACE FUNCTION f_get_sums(_schema text, _tbl text)
  RETURNS TABLE(names text[], sums bigint[]) AS
$BODY$
BEGIN

RETURN QUERY EXECUTE (
    SELECT 'SELECT ''{'
           || string_agg(quote_ident(c.column_name), ', ' ORDER BY c.column_name)
           || '}''::text[],
           ARRAY['
           || string_agg('sum(' || quote_ident(c.column_name) || ')'
                                                   , ', ' ORDER BY c.column_name)
           || ']
    FROM   '
           || quote_ident(_schema) || '.' || quote_ident(_tbl)
    FROM   information_schema.columns c
    WHERE  table_schema = _schema
    AND    table_name = _tbl
    AND    data_type = 'integer'
    );

END;
$BODY$
  LANGUAGE plpgsql;

Zadzwoń:

SELECT unnest(names) AS name, unnest (sums) AS col_sum
FROM   f_get_sums('public', 'somereport');

Zwroty:

   name        | col_sum
---------------+---------
 int_col1      |    6614
 other_int_col |    8364
 third_int_col | 2720642

Wyjaśnij

Trudność polega na zdefiniowaniu RETURN typ dla funkcji, natomiast liczba i nazwy zwracanych kolumn będą się różnić. Jeden szczegół, który trochę pomaga:potrzebujesz tylko integer kolumny.

Rozwiązałem to, tworząc tablicę bigint (sum(int_col) zwraca bigint ). Dodatkowo zwracam tablicę nazw kolumn. Oba posortowane alfabetycznie według nazwy kolumny.

W wywołaniu funkcji podzieliłem te tablice za pomocą unnest() przybywając do pięknego wyświetlanego formatu.

Dynamicznie tworzone i wykonywane zapytanie to zaawansowana sprawa. Nie daj się zwieść wielu warstwom cytatów. Zasadniczo masz EXECUTE który pobiera argument tekstowy zawierający zapytanie SQL do wykonania. Ten tekst z kolei jest dostarczany przez drugorzędne zapytanie SQL, które tworzy ciąg zapytania podstawowego.

Jeśli to za dużo na raz lub plpgsql jest dla Ciebie raczej nowy, zacznij od tej powiązanej odpowiedzi gdzie wyjaśnię podstawy dotyczące znacznie prostszej funkcji i podam linki do instrukcji dotyczących głównych funkcji.

Jeśli wydajność jest niezbędne, aby bezpośrednio przeszukiwać katalog Postgres (pg_catalog.pg_attributes ) zamiast używać standardowych (ale powolnych) information_schema.columns . Oto prosty przykład z pg_attributes .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zautomatyzowane aktualizacje klastrów PostgreSQL w chmurze niemal zerowe przestoje (część II)

  2. Hibernacja nie zapisuje obiektu w bazie danych?

  3. Postgres tablica json ostatnia data

  4. Tabela wiele do wielu — wydajność jest zła

  5. Zwracanie wielu wartości w funkcji