@ erwin-brandstetter: The return type of the function is not a problem if you always return the JSON type with the converted results.
Here is the function I came with:
CREATE OR REPLACE FUNCTION report.test( i_start_date TIMESTAMPTZ, i_end_date TIMESTAMPTZ, i_interval INT ) RETURNS TABLE ( tab JSON ) AS $ab$ DECLARE _key_id TEXT; _text_op TEXT = ''; _ret JSON; BEGIN -- SELECT DISTINCT for query results FOR _key_id IN SELECT DISTINCT at_name FROM report.company_data_date cd JOIN report.company_data_amount cda ON cd.id = cda.company_data_date_id JOIN report.amount_types at ON cda.amount_type_id = at.id WHERE date_start BETWEEN i_start_date AND i_end_date AND interval_type_id = i_interval LOOP -- build function_call with datatype of column IF char_length(_text_op) > 1 THEN _text_op := _text_op || ', ' || _key_id || ' NUMERIC(20,2)'; ELSE _text_op := _text_op || _key_id || ' NUMERIC(20,2)'; END IF; END LOOP; -- build query with parameter filters RETURN QUERY EXECUTE ' SELECT array_to_json(array_agg(row_to_json(t))) FROM ( SELECT * FROM crosstab(''SELECT date_start, at.at_name, cda.amount ct FROM report.company_data_date cd JOIN report.company_data_amount cda ON cd.id = cda.company_data_date_id JOIN report.amount_types at ON cda.amount_type_id = at.id WHERE date_start between $$' || i_start_date::TEXT || '$$ AND $$' || i_end_date::TEXT || '$$ AND interval_type_id = ' || i_interval::TEXT || ' ORDER BY date_start'') AS ct (date_start timestamptz, ' || _text_op || ') ) t;'; END; $ab$ LANGUAGE 'plpgsql';
So, when you run it, you get dynamic results in JSON, and you don't need to know how many values have been rotated:
select * from report.test(now()- '1 week'::interval, now(), 1); tab ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [{"date_start":"2015-07-27T08:40:01.277556-04:00","burn_rate":0.00,"monthly_revenue":5800.00,"cash_balance":0.00},{"date_start":"2015-07-27T08:50:02.458868-04:00","burn_rate":34000.00,"monthly_revenue":15800.00,"cash_balance":24000.00}] (1 row)
Change If you have mixed data types in your crosstab, you can add logic to view it for each column with something like this:
SELECT a.attname as column_name, format_type(a.atttypid, a.atttypmod) AS data_type FROM pg_attribute a JOIN pg_class b ON (a.attrelid = b.relfilenode) JOIN pg_catalog.pg_namespace n ON n.oid = b.relnamespace WHERE n.nspname = $$schema_name$$ AND b.relname = $$table_name$$ and a.attstattarget = -1;"
Caullyn Aug 02 '15 at 23:02 2015-08-02 23:02
source share