#oracle #function #plsql #boilerplate
#Oracle #функция #plsql #шаблонный
Вопрос:
У меня есть два одинаковых оператора запроса, отличаются только 3 столбца, которые я использую для создания сводных таблиц. Первые два столбца дают размеры сводной таблицы, в то время как третий столбец содержит данные, для которых мы вызываем агрегатную функцию.
Я новичок в SQL, поэтому мне интересно, есть ли какой-нибудь чистый способ определить функцию с параметрами 3 column name и 4-м параметром, который выдает агрегатную функцию.
SELECT *
FROM (
SELECT SDDCTO, SDSRP4, SDSOQS
FROM MyTable
)
PIVOT (
sum(SDSOQS)
for SDDCTO
IN ('EB' AS EB
'EL' AS EL,
'ER' AS ER,
'ES' AS ES,
'E1' AS E1,
'E2' AS E2,
'E5' AS E5
'E9' AS E9
)
)
ORDER BY SDSRP4
;
-- Same query with different columns and aggregate function
SELECT *
FROM (
SELECT SDDCTO, SDMCU, SDAEXP
FROM MyTable
)
PIVOT (
avg(SDAEXP)
for SDDCTO
IN ('EB' AS EB,
'EL' AS EL,
'ER' AS ER,
'ES' AS ES,
'E1' AS E1,
'E2' AS E2,
'E5' AS E5,
'E9' AS E9
)
)
ORDER BY SDMCU
;
Ответ №1:
Для проектов реального мира ранее вы освоитесь с dyanmic SQL и функциями в предложении from — в долгосрочной перспективе это лучше.
Я ненавижу писать один и тот же или похожий код дважды. Так что лучшим вариантом будет что-то вроде
select ...
from table(plsql_package ( parameters ))
Комментарии:
1. Какой, по вашему мнению, наилучший подход, документация или учебное пособие для начала изучения динамического SQL? Честно говоря, на первый взгляд это кажется немного жестковатым.
2. Времена изменились — теперь интерфейс execute immediate делает это довольно простым. Так что просто посмотрите документацию execute immediate и создавайте оттуда. Затем смотрите курсоры для этого. У вас есть хороший проект для создания, который облегчает процесс обучения.
Ответ №2:
При этом не используется функция, которая должна была бы использовать динамический SQL, вероятно, будет более сложной в обслуживании, чем два отдельных запроса; но вы могли бы создать представление, объединяющее оба агрегата в одном:
CREATE VIEW MyView AS
SELECT *
FROM (
SELECT SDDCTO, SDSRP4, SDSOQS, SDMCU, SDAEXP
FROM MyTable
)
PIVOT (
sum(SDSOQS) as SUM_SDOQS,
avg(SDAEXP) as AVG_SDAEXP
for SDDCTO
IN ('EB' AS EB,
'EL' AS EL,
'ER' AS ER,
'ES' AS ES,
'E1' AS E1,
'E2' AS E2,
'E5' AS E5,
'E9' AS E9
)
)
;
… и затем запрашивайте представление в ваших двух запросах вместо таблицы:
SELECT SDSRP4, EB_SUM_SDOQS, EL_SUM_SDOQS, ER_SUM_SDOQS, ES_SUM_SDOQS,
E1_SUM_SDOQS, E2_SUM_SDOQS, E5_SUM_SDOQS, E9_SUM_SDOQS
FROM MyView
ORDER BY SDSRP4
;
SELECT SDMCU, EB_AVG_SDAEXP, EL_AVG_SDAEXP, ER_AVG_SDAEXP, ES_AVG_SDAEXP,
E1_AVG_SDAEXP, E2_AVG_SDAEXP, E5_AVG_SDAEXP, E9_AVG_SDAEXP
FROM MyView
ORDER BY SDMCU
;
Хотя я не уверен, что это принесет вам столько пользы…
Комментарии:
1. Ну, я немного приврал, чтобы упростить вопросы. Честно говоря, я использую этот код уже в 11-й раз, потому что у меня много столбцов для создания сводных данных.
2. Вы могли бы добавить больше агрегатов к сводке в представлении и больше столбцов к внутреннему запросу; при условии, что всем им нужны одни и те же предложения pivot ‘in’ и ‘for’. Я думаю, что это либо это, либо (возможно, конвейерная) функция, использующая динамический SQL; но кто-то другой может придумать что-то, о чем я, конечно, не подумал.