Преобразование подтаблиц в той же таблице в столбцы

У меня есть такая таблица:

+-------+-------+-------+-------+
|  ID   | City  | Param | Value |
+-------+-------+-------+-------+
| id1   | city1 | a     | value |
| id2   | city1 | b     | value |
| id3   | city1 | c     | value |
| id4   | city2 | a     | value |
| id5   | city2 | b     | value |
| id6   | city2 | c     | value |
| ...   | ...   | ...   | ...   |
| idN   | cityN | a     | value |
| idN+1 | cityN | b     | value |
| idN+2 | cityN | c     | value |
+-------+-------+-------+-------+

Как вы можете видеть, он имеет подтаблицу для каждого города, например:

+-------+-------+
| Param | Value |
+-------+-------+
| a     | value |
| b     | value |
| c     | value |
+-------+-------+

Поэтому я хотел бы объединить все подтаблицы и получить таблицу, подобную этой:

+-------+-------+-------+-----+-------+
| Param | city1 | city2 | ... | cityN |
+-------+-------+-------+-----+-------+
| a     | value | value | ... | value |
| b     | value | value | ... | value |
| c     | value | value | ... | value |
+-------+-------+-------+-----+-------+

Любые идеи, как я могу получить это?

Заранее спасибо!

Примечание 1: Количество городов является переменным.

Примечание 2: Решением может быть функция PL/SQL.

2 ответа

Решение

Чтобы получить желаемый результат, вам нужно повернуть данные. В то время как вы сказали, что plsql может быть вариантом, вы не указали, какую версию Oracle вы используете. Начиная с Oracle 11g, PIVOT функция была сделана доступной.

Если вы не используете Oracle 119, то вы можете использовать агрегатную функцию с CASE выражение:

select param,
    max(case when city = 'city1' then value end) City1,
    max(case when city = 'city2' then value end) City2
from yourtable
group by param

Смотрите SQL Fiddle с демонстрацией.

Поскольку вы заявляете, что у вас будет неизвестное количество city значения, то вам нужно будет создать динамическую SQL-версию этого запроса. Вы можете создать процедуру, подобную этой:

CREATE OR REPLACE procedure dynamic_pivot(p_cursor in out sys_refcursor)
as
    sql_query varchar2(1000) := 'select param ';

    begin
        for x in (select distinct city from yourtable order by 1)
        loop
            sql_query := sql_query ||
                ' , max(case when city = '''||x.city||''' then value else null end) as '||x.city;

                dbms_output.put_line(sql_query);
        end loop;

        sql_query := sql_query || ' from yourtable group by param order by param';
        dbms_output.put_line(sql_query);

        open p_cursor for sql_query;
    end;
/

Затем, чтобы получить свой результат, вы можете использовать следующее (примечание: я использовал это в TOAD):

variable x refcursor
exec dynamic_pivot(:x)
print x

И результат вашего запроса будет:

| PARAM | CITY1 | CITY2 |
-------------------------
|     a | value | value |
|     b | value | value |
|     c | value | value |

Вы можете использовать новый pivot в 11G или model оговорка, если у вас есть 10G. проверьте документы.

Другие вопросы по тегам