#sql #oracle #plsql
Вопрос:
Обычно мои процедуры (Oracle 12c) выглядят следующим образом:
PROCEDURE xxx AS
declare variables
BEGIN
save log
create table 1
save log
...
create table 2
save log
...
create table n
save log
END xxx
Я создаю таблицы от 1 до n-1 в качестве вспомогательных таблиц (производительность и модульность) для получения желаемой n-й таблицы. Использую ли я обычные таблицы, когда я должен использовать глобальные временные таблицы?
PD: Мой первый вопрос был закрыт из-за того, что он основан на мнении, я изменил его, чтобы сделать его более конкретным.
ИЗМЕНИТЬ: добавление примера процедуры
create or replace PACKAGE BODY balance_mismatch_dca AS
idproceduregeneral VARCHAR2(50);
PROCEDURE aux_tables AS
balance_zufi_dca_exists INTEGER;
balance_dfkkop_dca_exists INTEGER;
BEGIN
idproceduregeneral := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
uxxxxxx_logs('Start Aux Tables', idproceduregeneral);
BEGIN
SELECT
COUNT(*)
INTO balance_zufi_dca_exists
FROM
sys.all_tables
WHERE
table_name = upper('balance_zufi_dca');
EXCEPTION
WHEN no_data_found THEN
balance_zufi_dca_exists := 0;
END;
IF ( balance_zufi_dca_exists ) = 1 THEN
EXECUTE IMMEDIATE q'[Drop Table balance_zufi_dca]';
END IF;
EXECUTE IMMEDIATE q'[
CREATE TABLE balance_zufi_dca
AS
WITH aux AS (
SELECT
vkont,
vtref,
MAX(zzmfvdat) AS lat
FROM
cdc.uap_zufi_t_dca_place@rbip
WHERE
zzextamount != 0
GROUP BY
vkont,
vtref
), aux2 AS (
SELECT
a.vkont,
a.vtref,
a.lat,
MAX(b.zzextamount) AS amount_zufi,
MAX(b.zzplacref) AS dca,
MAX(zzplace_typ) AS placement
FROM
aux a
JOIN cdc.uap_zufi_t_dca_place@rbip b ON ( b.vkont = a.vkont
AND b.vtref = a.vtref
AND b.zzmfvdat = a.lat )
GROUP BY
a.vkont,
a.vtref,
a.lat
)
SELECT
vkont,
SUM(amount_zufi) AS amount_zufi,
MAX(dca) AS dca,
MAX(placement) AS placement
FROM
aux2
GROUP BY
vkont
]'
;
uxxxxxx_logs('End Balance Zufi DCA', idproceduregeneral);
BEGIN
SELECT
COUNT(*)
INTO balance_dfkkop_dca_exists
FROM
sys.all_tables
WHERE
table_name = upper('balance_dfkkop_dca');
EXCEPTION
WHEN no_data_found THEN
balance_dfkkop_dca_exists := 0;
END;
IF ( balance_dfkkop_dca_exists ) = 1 THEN
EXECUTE IMMEDIATE q'[Drop Table balance_dfkkop_dca]';
END IF;
EXECUTE IMMEDIATE q'[
Create Table balance_dfkkop_dca AS
WITH aux AS (
SELECT /* FULL(a) */
vkont,
betrw as amount_dfkkop
FROM
cdc.uap_dfkkop@rbip a
WHERE
augrs IS NULL
AND augst IS NULL
AND stakz IS NULL
AND abwbl IS NULL
AND (studt <= to_char(sysdate, 'YYYYMMDD') or studt is null)
AND faedn <= to_char(sysdate, 'YYYYMMDD')
)
SELECT
*
FROM
aux
]'
;
uxxxxxx_logs('End Balance DFKKOP DCA', idproceduregeneral);
END aux_tables;
PROCEDURE gen_view AS
BEGIN
idproceduregeneral := utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE VIEW vw_bm_dca_volumes AS
WITH aux AS (
SELECT
a.vkont,
a.amount_zufi,
SUM(nvl(b.amount_dfkkop, 0)) AS amount_dfkkop
FROM
balance_zufi_dca a
LEFT JOIN balance_dfkkop_dca b ON ( b.vkont = a.vkont )
GROUP BY
a.vkont,
a.amount_zufi
)
SELECT
CASE
WHEN amount_zufi = amount_dfkkop THEN
'Chased for the Correct Balance'
WHEN amount_zufi > amount_dfkkop THEN
'Chased for Higher Balance'
WHEN amount_zufi < amount_dfkkop THEN
'Chased for Lower Balance'
ELSE
NULL
END AS status,
COUNT(1) AS ca_count,
round(RATIO_TO_REPORT(COUNT(1)) OVER() * 100, 2) perc
FROM
aux
GROUP BY
CASE
WHEN amount_zufi = amount_dfkkop THEN
'Chased for the Correct Balance'
WHEN amount_zufi > amount_dfkkop THEN
'Chased for Higher Balance'
WHEN amount_zufi < amount_dfkkop THEN
'Chased for Lower Balance'
ELSE
NULL
END
ORDER BY
COUNT(1) DESC
]'
;
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE VIEW vw_bm_dca_data AS
WITH aux AS (
SELECT
a.vkont,
a.dca,
a.placement,
a.amount_zufi,
SUM(nvl(b.amount_dfkkop, 0)) AS amount_dfkkop
FROM
balance_zufi_dca a
LEFT JOIN balance_dfkkop_dca b ON ( b.vkont = a.vkont )
GROUP BY
a.vkont,
a.dca,
a.placement,
a.amount_zufi
)
SELECT
*
FROM
aux
WHERE
amount_zufi != amount_dfkkop
]'
;
uxxxxxx_logs('End Views', idproceduregeneral);
END gen_view;
END balance_mismatch_dca;
Ответ №1:
Это зависит. Например:
- если этими таблицами пользуетесь только «вы», то это на самом деле не имеет значения.
- если есть много пользователей, которые работают с одной и той же процедурой, то
- если вы используете «обычные» таблицы, у вас должен быть какой — то идентификатор (идентификатор, имя пользователя, что угодно), который будет отличать данные одного пользователя от данных другого, потому что — если вы этого не сделаете-они изменят все строки для всех пользователей, и вы получите серьезные проблемы (от несоответствия до блокировки). Если вы вручную не удалите строки из таблиц, они останутся заполненными
- если вы используете (глобальные) временные таблицы, каждый пользователь будет видеть только свои собственные данные, а их содержимое (таблиц) будет потеряно при завершении сеанса (или транзакции; в зависимости от того, как вы создали таблицы)
Так что, как я уже сказал, все зависит от обстоятельств.
Комментарии:
1. Большое спасибо за ваш ответ. Это просто я работаю над процедурой. Однажды мне сказали, что создание «обычных» таблиц внутри хранимой процедуры было «очень странным», и я пытался выяснить, есть ли какой-либо лучший подход при работе с хранимыми процедурами..
2. Это почти наверняка неправильный подход. В Oracle мы создаем таблицы «один раз» (на уровне SQL) и используем их «много раз», независимо от того, являются ли они обычными или глобальными временными таблицами. Я думал, что ваши операторы «создать таблицу 1» на самом деле представляют собой «вставить в таблицу 1». Не создавайте таблицы в PL/SQL. Если вы это сделаете, вам нужно будет использовать динамический SQL.
3. Как я могу вставить/обновить/удалить эти таблицы? Используя слияние? Я отредактировал свой первоначальный вопрос, добавив пример хранимой процедуры с моим текущим подходом. Какие изменения следует внести для достижения этой цели?
4. Как я уже сказал: не создавайте таблицы в PL/SQL. В процедуре вы просто ВСТАВЛЯЕТЕ, ОБЪЕДИНЯЕТЕ или ОБНОВЛЯЕТЕ все, что считаете нужным в определенный момент.
5. Я не говорил, что динамического SQL вообще следует избегать; иногда это необходимо. На мой взгляд, создание любых объектов из PL/SQL — это, в общем — то, плохая идея, плохой подход, ничего не улучшает, многое усложняет, и я этого избегаю. Обычно.