Динамическое вращение строк в столбцы в Oracle - PullRequest
23 голосов
/ 11 октября 2011

У меня есть следующая таблица Oracle 10g с именем _kv:

select * from _kv

ID       K       V
----     -----   -----
  1      name    Bob
  1      age     30
  1      gender  male
  2      name    Susan
  2      status  married

Я бы хотел превратить мои ключи в столбцы, используя простой SQL (не PL / SQL), чтобы полученная таблица выглядела примерно такthis:

ID       NAME    AGE    GENDER  STATUS
----     -----   -----  ------  --------
  1      Bob      30     male 
  2      Susan                   married
  • В запросе должно быть столько столбцов, сколько уникальных K существует в таблице (их не так много)
  • Нет способа узнатькакие столбцы могут существовать до выполнения запроса.
  • Я пытаюсь избежать запуска начального запроса для программной сборки окончательного запроса.
  • Пустые ячейки могут быть пустыми или пустыми строками, не так ли?это действительно имеет значение.
  • Я использую Oracle 10g, но решение 11g также будет в порядке.

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

Спасибо!

Ответы [ 4 ]

29 голосов
/ 11 октября 2011

Oracle 11g предоставляет PIVOT операцию, которая делает то, что вы хотите.

Решение Oracle 11g

select * from
(select id, k, v from _kv) 
pivot(max(v) for k in ('name', 'age', 'gender', 'status')

(Примечание: у меня нет копии 11g, чтобы проверить это, поэтому я не проверил ее функциональность)

Я получил это решение от: http://orafaq.com/wiki/PIVOT

РЕДАКТИРОВАТЬ - опция pivot xml (также Oracle 11g)
Очевидно, есть также опция pivot xml, когда вы не знаете всех возможных заголовков столбцов, которые могут вам понадобиться. (см. раздел XML TYPE в нижней части страницы, расположенный по адресу http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html)

select * from
(select id, k, v from _kv) 
pivot xml (max(v)
for k in (any) )

(Примечание. Как и раньше, у меня нет копии 11g, чтобы проверить это, поэтому я не проверял ее функциональность)

Edit2: Изменено v в операторах pivot и pivot xml на max(v), поскольку предполагается, что оно будет агрегировано, как указано в одном из комментариев. Я также добавил предложение in, которое не является обязательным для pivot. Конечно, необходимость указывать значения в предложении in отрицательно сказывается на цели создания полностью динамического запроса сводной / перекрестной таблицы, как было желание автора этого вопроса.

6 голосов
/ 02 июня 2015

Чтобы справиться с ситуациями, когда существует возможность нескольких значений (v в вашем примере), я использую PIVOT и LISTAGG:

SELECT * FROM
(
  SELECT id, k, v
  FROM _kv 
)
PIVOT 
(
  LISTAGG(v ,',') 
  WITHIN GROUP (ORDER BY k) 
  FOR k IN ('name', 'age','gender','status')
)
ORDER BY id;

Поскольку вам нужны динамические значения, используйте динамический SQL и передайте значения, определенные путем выполнения выбора данных таблицы перед вызовом оператора сводки.

5 голосов
/ 24 сентября 2013

Бывают задачи на разворот. Ниже работает у меня как проверено только сейчас на 11g:

select * from
(
  select ID, COUNTRY_NAME, TOTAL_COUNT from ONE_TABLE 
) 
pivot(
  SUM(TOTAL_COUNT) for COUNTRY_NAME in (
    'Canada', 'USA', 'Mexico'
  )
);
3 голосов
/ 23 апреля 2017

Прежде всего, необходимо выполнить синтаксический анализ динамического поворота с использованием pivot xml.У нас есть другой способ сделать это, сохраняя имена столбцов в переменной и передавая их в динамический sql, как показано ниже.

Рассмотрим следующую таблицу:

enter image description here

Если нам нужно показать значения в столбце YR в качестве имен столбцов и значения в этих столбцах из QTY, то мы можем использовать приведенный ниже код.

declare
  sqlqry clob;
  cols clob;
begin
  select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
  into   cols
  from   (select distinct YR from EMPLOYEE);


  sqlqry :=
  '      
  select * from
  (
      select *
      from EMPLOYEE
  )
  pivot
  (
    MIN(QTY) for YR in (' || cols  || ')
  )';

  execute immediate sqlqry;
end;
/

РЕЗУЛЬТАТ

enter image description here

...