2016-11-07 5 views
1

На основании this У меня есть таблица, которая имеет значения, которые будут именами столбцов результата запроса PostgreSQL.значения столбца как имена столбцов в запросе thepsql

id col1  col2 
---------------------- 
0  name ax 
0  name2 bx 
0  name3 cx 
1  name dx 
1  name2 ex 
1  name2 fx 
...  ...  ... 

Теперь я хочу, чтобы результат запроса, чтобы выглядеть следующим образом

id name name2  name3 ... 
0 ax  bx   cx  ... 
1 dx  ex   fx  ... 

Число полей на col1 изменяется каждый раз, когда добавляется новое поле. Для этого мне нужно сгенерировать функцию, которая будет динамически возвращать результаты таким образом.

Это было что:

SELECT 
    id, 
    /* if col1 matches the name string of this CASE, return col2, otherwise return NULL */ 
    /* Then, the outer MAX() aggregate will eliminate all NULLs and collapse it down to one row per id */ 
    MAX(CASE WHEN (col1 = 'name') THEN col2 ELSE NULL END) AS name, 
    MAX(CASE WHEN (col1 = 'name2') THEN col2 ELSE NULL END) AS name2, 
    MAX(CASE WHEN (col1 = 'name3') THEN col2 ELSE NULL END) AS name3 
FROM mytable 
GROUP BY id 

, но мне нужно, чтобы он динамический, потому что col1 имена могут быть большой список, так что я не могу обновлять запрос, каждый раз, когда новое имя добавляется в col1.

Я проверил, как это сделать, используя сводную таблицу, я попытался следовать этому example, но также там хорошо известны поля, пожалуйста, кто-нибудь может мне помочь?

+0

Для вызова запроса с динамическим количеством столбцы, вы должны использовать [динамическую команду] (https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXE CUTING-DYN) и [refcursor] (https://www.postgresql.org/docs/current/static/plpgsql-cursors.html#AEN66382) или [курсор sql] (https://www.postgresql.org/docs /current/static/sql-declare.html), чтобы получить результат. – Abelisto

+1

Вы указали ODBC как один из ваших тегов ... вы приносите это в Excel или Access? Если это так, вы можете динамически связывать данные через ODBC и позволить этим инструментам визуализировать его так, как вы просите, - в сводной таблице или запросе кросс-табуляции. – Hambone

ответ

1

Для 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 $$; 

Использование (с некоторой отладочной):

[email protected]=# start transaction; 
START TRANSACTION 
*[email protected]=# 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) 

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

*[email protected]=# rollback; 
0

этот запрос ответить на ваши потребности совершенно

SELECT 
    table_id.id, 
    table_name.name, 
    table_name2.name2, 
    table_name3.name3 
FROM left join (SELECT DISTINCT id FROM mytable) table_id 
left join (SELECT id, MAX(col2) AS name FROM mytable where col1 = 'name' GROUP BY id) table_name on table_name2.id = table_id.id 
left join (SELECT id, MAX(col2) AS name2 FROM mytable where col1 = 'name2' GROUP BY id) table_name2 on table_name2.id = table_id.id 
left join (SELECT id, MAX(col2) AS name3 FROM mytable where col1 = 'name3' GROUP BY id) table_name3 on table_name2.id = table_id.id 
+0

Спасибо за ваш ответ, но я думаю, что вы не получили то, что я спросил. если у меня есть тысяча столбцов с именем «имяxxx», как я должен писать эти «table_name.name», table_name2.name2, table_name3.name3'? –