#sql #oracle #pivot
Вопрос:
У меня есть приведенная ниже таблица t1:
A | B | C | V |
---|---|---|---|
A1 | В1 | C1 | V1 |
A2 | В1 | C2 | V2 |
A3 | B2 | C1 | V3 |
А4 | B2 | C2 | V4 |
A1 | В1 | C1 | V10 |
A1 | В1 | C2 | V11 |
Я хотел бы получить следующий результат:
A | B1_C1 | B1_C2 | B2_C1 | B2_C2 |
---|---|---|---|---|
A1 | V1 | V11 | нулевой | нулевой |
A2 | нулевой | V2 | нулевой | нулевой |
A3 | нулевой | нулевой | V3 | нулевой |
А4 | нулевой | нулевой | нулевой | V4 |
Я хотел бы, чтобы минимум V группировался по A, будучи столбцами комбинаций B, C
Ответ №1:
Если вы знаете нужные столбцы, используйте условную агрегацию:
select a,
max(case when b = 'B1' and c = 'C1' then v end) as b1_c1,
max(case when b = 'B1' and c = 'C2' then v end) as b1_c2,
max(case when b = 'B2' and c = 'C1' then v end) as b2_c1,
max(case when b = 'B2' and c = 'C2' then v end) as b2_c2
from t
group by a;
Комментарии:
1. На самом деле, я не знаю столбцов, мне нужен динамический способ 🙁
Ответ №2:
В основном вам необходимо объединить b
столбцы и c
столбцы, а затем выполнить поворот по этим столбцам, группируя их по столбцу a
, например
WITH t2 AS
(
SELECT b||'_'||c AS bc, a, v
FROM t1
)
SELECT a,
MIN(DECODE(bc,'B1_C1',v)) AS b1_c1,
MIN(DECODE(bc,'B1_C2',v)) AS b1_c2,
MIN(DECODE(bc,'B2_C1',v)) AS b2_c1,
MIN(DECODE(bc,'B2_C2',v)) AS b2_c2
FROM t2
GROUP BY a
ORDER BY a
Вы можете создать такую сохраненную функцию, которая возвращает SYS_REFCURSOR
результат типа, используя приведенную выше инструкцию select в качестве основного запроса вместе со вспомогательным запросом для создания агрегированных условных выражений, чтобы выполнить это динамически ;
CREATE OR REPLACE FUNCTION Get_Pivoted_Values RETURN SYS_REFCURSOR IS
v_recordset SYS_REFCURSOR;
v_sql VARCHAR2(32767);
v_cols VARCHAR2(32767);
BEGIN
SELECT LISTAGG( 'MIN(DECODE(bc,'''||bc||''',v)) AS '||bc , ',' )
WITHIN GROUP ( ORDER BY bc )
INTO v_cols
FROM ( SELECT b||'_'||c AS bc
FROM t1
GROUP BY b||'_'||c
ORDER BY bc );
v_sql :='WITH t2 AS
(
SELECT b||''_''||c AS bc, t.*
FROM t1
)
SELECT a,'|| v_cols ||'
FROM t2
GROUP BY a
ORDER BY a';
OPEN v_recordset FOR v_sql;
RETURN v_recordset;
END;
/
Затем запустите приведенный ниже код ;
VAR rc REFCURSOR
EXEC :rc := Get_Pivoted_Values;
PRINT rc
из командной строки разработчика SQL, чтобы увидеть ожидаемый набор результатов.
Ответ №3:
Это можно сделать «динамически», но, например PIVOT
, с фиксированным максимальным количеством столбцов :
WITH t1 AS (SELECT 'A1' A , 'B1' B, 'C1' C, 'V1' V FROM DUAL
UNION ALL SELECT 'A2', 'B1', 'C2', 'V2' FROM DUAL
UNION ALL SELECT 'A3', 'B2', 'C1', 'V3' FROM DUAL
UNION ALL SELECT 'A4', 'B2', 'C2', 'V4' FROM DUAL
UNION ALL SELECT 'A1', 'B1', 'C1', 'V10' FROM DUAL
UNION ALL SELECT 'A1', 'B1', 'C2', 'V11' FROM DUAL),
t2 AS (SELECT t1.A, t1.B||'_'||t1.C col, t1.V
FROM t1),
t3 AS (SELECT ROWNUM colnum, col FROM (SELECT DISTINCT t2.col FROM t2 ORDER BY t2.col))
SELECT NULL A,
(SELECT t3.col FROM t3 WHERE colnum = 1) col1,
(SELECT t3.col FROM t3 WHERE colnum = 2) col2,
(SELECT t3.col FROM t3 WHERE colnum = 3) col3,
(SELECT t3.col FROM t3 WHERE colnum = 4) col4,
(SELECT t3.col FROM t3 WHERE colnum = 5) col5,
(SELECT t3.col FROM t3 WHERE colnum = 6) col6,
(SELECT t3.col FROM t3 WHERE colnum = 7) col7,
(SELECT t3.col FROM t3 WHERE colnum = 8) col8
FROM DUAL
UNION ALL
SELECT *
FROM (
SELECT A, MAX(col1_v) col1, MAX(col2_v) col2, MAX(col3_v) col3, MAX(col4_v) col4,
MAX(col5_v) col5, MAX(col6_v) col6, MAX(col7_v) col7, MAX(col8_v) col8
FROM (SELECT *
FROM (SELECT t2.A, t2.V, t3.col, t3.colnum
FROM t2 JOIN t3 ON t3.col = t2.col)
PIVOT (
MIN(V) AS V
FOR colnum IN (1 AS col1, 2 AS col2, 3 AS col3, 4 AS col4, 5 AS col5, 6 AS col6, 7 AS col7, 8 AS col8)
) )
GROUP BY A
ORDER BY A
)
Здесь для 8 различных комбинаций B и C макс. первая строка выходных данных описывает, в каком столбце какая комбинация B и C, следующие строки-ваши ожидаемые результаты. Вы можете адаптировать его с максимальным количеством возможных комбинаций B и C, просто добавьте столбцы.
Предупреждение: Если количество комбинаций B и C превышает фиксированное количество столбцов, запрос будет выполнен, но вывод будет ограничен количеством комбинаций, разрешенных текущим количеством столбцов.
Скрипка, если вы хотите ее протестировать.
Комментарии:
1. Также возможно иметь динамическое количество столбцов и динамическое именование для них с помощью полиморфных функций Oracle , но для этого требуется написать код PLSQL в вашей БД.
2. Или макросы SQL тоже (спасибо @WilliamRobertson за идею) .