column values as column names in thepsql query

ぐ巨炮叔叔 提交于 2019-12-02 06:59:54

For PostgreSQL 9.4+

-- Test data
create table t(id int, col1 text, col2 text);
insert into t values
  (0, 'name', 'ax'),
  (0, 'name2', 'bx'),
  (0, 'name3', 'cx'),
  (1, 'name', 'dx'),
  (1, 'name2', 'ex'),
  (1, 'name3', 'fx');

create or replace function fn_pivot(
  p_sql text,
  p_row_field text,
  p_col_field text,
  p_data_field text,
  p_cursor refcursor) returns refcursor language plpgsql as $$
declare
  cols text[];
  a text[];
  q text;
  --f text;
begin
  -- Get dynamic columns
  q := format('select array_agg(distinct %s::text) from (%s) t', p_col_field, p_sql);
  execute q into cols;
  -- Generate SELECT part
  select array_agg(format('%s filter (where %s::text = %L) as %I', p_data_field, p_col_field, x, x)) into a from unnest(cols) as t(x);
  q := format('%s, %s', p_row_field, array_to_string(a, ', '));
  -- Complete the whole statement
  q := format('select %s from (%s) t group by %s order by %s', q, p_sql, p_row_field, p_row_field);
  raise info '%', q;
  open p_cursor for execute q;
  return p_cursor;
end $$;

Usage (with some debug output):

nd@postgres=# start transaction;
START TRANSACTION
*nd@postgres=# select * from fn_pivot('select * from t', 'id', 'col1', 'max(col2)', 'cur');
INFO:  select id, max(col2) filter (where col1::text = 'name') as name, max(col2) filter (where col1::text = 'name2') as name2, max(col2) filter (where col1::text = 'name3') as name3 from (select * from t) t group by id order by id
╔══════════╗
║ fn_pivot ║
╠══════════╣
║ cur      ║
╚══════════╝
(1 row)

*nd@postgres=# fetch all in cur;
╔════╤══════╤═══════╤═══════╗
║ id │ name │ name2 │ name3 ║
╠════╪══════╪═══════╪═══════╣
║  0 │ ax   │ bx    │ cx    ║
║  1 │ dx   │ ex    │ fx    ║
╚════╧══════╧═══════╧═══════╝
(2 rows)

*nd@postgres=# rollback;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!