Oracle SP использование глобальных временных таблиц

#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 — это, в общем — то, плохая идея, плохой подход, ничего не улучшает, многое усложняет, и я этого избегаю. Обычно.