2010-12-10 3 views
2

У меня есть таблица, как:Транспонирование таблицы с помощью запроса на выборку

Key type  value 
--------------------- 
40  A  12.34  
41  A  10.24  
41  B  12.89 

Я хочу это в формате:

Types  40 41  42 (keys) 
--------------------------------- 
A  12.34 10.24 XXX  
B  YYY  12.89 ZZZ 

Как это может быть сделано с помощью запроса SQL. Заявления, декодирование?

ответ

3

Что вы ищете называется "pivot" (смотри также "Pivoting Operations" в базе данных Oracle Guide хранилищ данных):

SELECT * 
    FROM tbl 
    PIVOT(SUM(value) FOR Key IN (40, 41, 42)) 

Он был добавлен в Oracle в 11g. Обратите внимание, что вам нужно указать столбцы результатов (значения из неавторизованного столбца, которые становятся поворотными именами столбцов) в предложении pivot. Любые столбцы, не указанные в своде, неявно сгруппированы. Если в исходной таблице есть столбцы, которые вы не хотите группировать, выберите из представления или подзапроса, а не из таблицы.

Вы можете принять участие в бит wizardry и получить Oracle для создания инструкции для вас, так что вам не нужно определять, какие значения столбцов для поворота. В 11g, когда вы знаете, значение столбцов являются числовым:

SELECT 
    'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN (' 
    || LISTAGG(Key, ',') WITHIN GROUP (ORDER BY Key) 
    || ');' 
    FROM tbl; 

Если значение столбцов не может быть числовым:

SELECT 
    'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN (\'' 
    || LISTAGG(Key, '\',\'') WITHIN GROUP (ORDER BY Key) 
    || '\'));' 
    FROM tbl; 

LISTAGG вероятно повторяет дубликаты (? Бы кто-то проверить это), в этом случае вам нужно:

SELECT 
    'SELECT * FROM tbl PIVOT(SUM(value) FOR Key IN (\'' 
    || LISTAGG(Key, '\',\'') WITHIN GROUP (ORDER BY Key) 
    || '\'));' 
    FROM (SELECT DISTINCT Key FROM tbl); 

вы могли бы пойти дальше, определяя функцию, которая принимает имя таблицы, совокупное выражение и поворотное имя столбца, который возвращает шарнирное заявление первого р затем оценивая вышеуказанное утверждение. Затем вы можете определить процедуру, которая принимает одни и те же аргументы и создает скошенный результат. У меня нет доступа к Oracle 11g, чтобы проверить это, но я считаю, что это будет выглядеть примерно так:

CREATE PACKAGE dynamic_pivot AS 
    -- creates a PIVOT statement dynamically 
    FUNCTION pivot_stmt (tbl_name IN varchar2(30), 
         pivot_col IN varchar2(30), 
         aggr IN varchar2(40), 
         quote_values IN BOOLEAN DEFAULT TRUE) 
     RETURN varchar2(300); 
    PRAGMA RESTRICT_REFERENCES (pivot_stmt, WNDS, RNPS); 

    -- creates & executes a PIVOT 
    PROCEDURE pivot_table (tbl_name IN varchar2(30), 
         pivot_col IN varchar2(30), 
         aggr IN varchar2(40), 
         quote_values IN BOOLEAN DEFAULT TRUE); 
END dynamic_pivot; 

CREATE PACKAGE BODY dynamic_pivot AS 
    FUNCTION pivot_stmt (
     tbl_name IN varchar2(30), 
     pivot_col IN varchar2(30), 
     aggr_expr IN varchar2(40), 
     quote_values IN BOOLEAN DEFAULT TRUE 
    ) RETURN varchar2(300) 
    IS 
    stmt VARCHAR2(400); 
    quote VARCHAR2(2) DEFAULT ''; 
    BEGIN 
    IF quote_values THEN 
     quote := '\\\''; 
    END IF; 
    -- "\||" shows that you are still in the dynamic statement string 
    -- The input fields aren't sanitized, so this is vulnerable to injection 
    EXECUTE IMMEDIATE 'SELECT \'SELECT * FROM ' || tbl_name 
      || ' PIVOT(' || aggr_expr || ' FOR ' || pivot_col 
      || ' IN (' || quote || '\' \|| LISTAGG(' || pivot_col 
         || ', \'' || quote || ',' || quote 
      || '\') WITHIN GROUP (ORDER BY ' || pivot_col || ') \|| \'' || quote 
      || '));\' FROM (SELECT DISTINCT ' || pivot_col || ' FROM ' || tbl_name || ');' 
     INTO stmt; 
    RETURN stmt; 
    END pivot_stmt; 

    PROCEDURE pivot_table (tbl_name IN varchar2(30), pivot_col IN varchar2(30), aggr_expr IN varchar2(40), quote_values IN BOOLEAN DEFAULT TRUE) IS 
    BEGIN 
    EXECUTE IMMEDIATE pivot_stmt(tbl_name, pivot_col, aggr_expr, quote_values); 
    END pivot_table; 
END dynamic_pivot; 

Примечание: длина параметров в tbl_name, pivot_col и aggr_expr приходит от maximum table and column name length. Также обратите внимание, что функция уязвима для SQL-инъекции.

В пред-11г вы можете применить методы MySQL pivot statement generation (который производит тип запроса, опубликованного другими пользователями, на основе явно заданного отдельного столбца для каждого значения поворота).

+2

Работает для Oracle 11, но для более ранних версий здесь приводится путь http://www.orafaq.com/wiki/PIVOT – 2010-12-10 14:20:01

0

Никогда не пробовал, но это, кажется, по крайней мере, Oracle 11 есть пункт PIVOT

1

Pivot делает упростить вещи значительно. Однако до 11g вам нужно сделать это вручную.

select 
    type, 
    sum(case when key = 40 then value end) as val_40, 
    sum(case when key = 41 then value end) as val_41, 
    sum(case when key = 42 then value end) as val_42 
from my_table 
group by type; 
0

Если у вас нет доступа к 11g, вы можете использовать агрегацию строк и метод группировки прибл.то, что вы ищете, такие как

with data as(
SELECT 40 KEY , 'A' TYPE , 12.34 VALUE FROM DUAL UNION 
SELECT 41 KEY , 'A' TYPE , 10.24 VALUE FROM DUAL UNION 
SELECT 41 KEY , 'B' TYPE , 12.89 VALUE FROM DUAL 
) 
      select 
       TYPE ,     
       wm_concat(KEY) KEY , 
       wm_concat(VALUE) VALUE 
       from data  
     GROUP BY TYPE; 

type  KEY  VALUE 
------ ------- ----------- 
A  40,41 12.34,10.24 
B  41  12.89    

Это основано на wm_concat, как показано здесь: http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php

Я собираюсь оставить это здесь только в случае, если это помогает, но я думаю, PIVOT или MikeyByCrikey ответы будут наилучшим образом удовлетворить ваши потребности после повторного просмотра ваших результатов.

Смежные вопросы