Передайте имя таблицы и переменную отметки времени в PL / SQL - PullRequest
0 голосов
/ 05 августа 2020

Я пишу приведенный ниже код PL / SQL в SQL разработчике для удаления данных из таблицы со столбцом временной метки в условии where. Как я могу изменить этот код, чтобы передать имя таблицы и значение отметки времени значениям, которые я хочу, в зависимости от того, из какой таблицы и записей времени я хочу удалить данные и создать хранимую процедуру, которую можно использовать повторно.

DBMS_OUTPUT.ENABLE;
    
DECLARE
    counter   INTEGER := 0;
    stop      INTEGER;
BEGIN
    dbms_output.put_line('START');
    LOOP
        counter   := counter + 1;
        DELETE my_schema.test
        WHERE t = '10-JUN-20 04.33.46.000000000 AM'
              AND   ROWNUM <= 100000;

        SELECT COUNT(*) 
        INTO   stop
        FROM my_schema.test
        WHERE t = '10-JUN-20 04.33.46.000000000 AM';

        EXIT WHEN stop <= 0;
        COMMIT;
    END LOOP;

    dbms_output.put_line('Counter: ' || counter);
    dbms_output.put_line('Left: ' || stop);
    COMMIT;
END;

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

Адаптация вашего анонима к хранимой процедуре, как указано, потребует преобразования его в динамический c SQL. Всегда сложнее. И при условии SQL впрыска. Для этого вы должны проверить параметры замены строки. У меня есть пара других изменений:

  • Передайте желаемое как метку времени, а не строку, это позволяет / заставляет вызывающую процедуру определять формат и необходимое преобразование, если таковое имеется.
  • Также добавлен параметр для имени столбца. Это освобождает именование столбцов от требований процедуры.
  • Нет необходимости подсчитывать оставшиеся элементы. Ваш l oop обрабатывает, пока это значение не достигнет 0, но это может быть определено количеством строк, удаленных на последнем проходе. Удалить устанавливает sql% rowcount равным количеству удаленных строк. Когда проход удаляет 0 строк, процесс завершается.
  • Удалено отображение результатов и фиксация из процедуры, снова передавая это вызывающей стороне.
create or replace
procedure delete_values_by_timestamp
          ( p_table_name   in varchar2
          , p_column_name  in varchar2
          , p_timestamp    in timestamp
          , p_result_msg  out varchar2
          )

IS
    table_name_parameter_invalid  exception;
    pragma exception_init(table_name_parameter_invalid,  -44002);
    column_name_parameter_invalid exception;
    pragma exception_init(column_name_parameter_invalid, -44003);    

    k_nl                        constant varchar2(1) := chr(10);
    k_max_delete_per_interation constant integer     := 100000;
    k_base_delete varchar2(256) :=
                 'delete from <table_name>'     ||
                  ' where <column_name> <= :1'  ||
                  '  and rownum <= :2';

    v_delete_sql    varchar2 (256) ;
    v_rows_deleted  integer  := 0;

begin 
    v_delete_sql := replace(replace(k_base_delete,'<table_name>', dbms_assert.sql_object_name(p_table_name))
                         ,'<column_name>',dbms_assert.simple_sql_name(p_column_name));

    dbms_output.put_line('Running SQL:' || k_nl || v_delete_sql);
    loop
       execute immediate v_delete_sql using p_timestamp, k_max_delete_per_interation;
       exit when sql%rowcount = 0;
       v_rows_deleted :=v_rows_deleted + sql%rowcount;       
    end loop;

    if v_rows_deleted = 0
    then
        p_result_msg := 'No Data Found';
    else
        p_result_msg := 'Number of Rows Deleted ' || to_char(v_rows_deleted);
    end if;
exception
    when table_name_parameter_invalid then
         raise_application_error(-20199,'Invalid Table Name (' || p_table_name || ') specified.');
    when column_name_parameter_invalid then
         raise_application_error(-20198,'Invalid Column Name (' || p_column_name || ') specified.');        
         
end delete_values_by_timestamp;

См. пример : В этом примере я уменьшаю количество строк, удаляемых на каждой итерации, со 100000 до 20. Дополнительным усовершенствованием будет передача количества строк для каждой итерации в качестве параметра.

0 голосов
/ 05 августа 2020

Я не мог проверить это, но вы могли создать функцию, которая принимает имя таблицы и временную метку в качестве параметра. Пока вы хотите удалить каждую запись с данной отметкой времени, вам не нужно l oop для каждой записи. Эта функция должна быть просто примером.

FUNCTION delete_values_by_timestamp (p_table_name   IN VARCHAR2 DEFAULT NULL,
                                     p_timestamp    IN VARCHAR2 DEFAULT NULL)
    RETURN VARCHAR2
IS
    v_count   NUMBER := 0;
    v_query   VARCHAR2 (500) := '';
BEGIN
    IF p_table_name IS NOT NULL
    THEN
        IF p_timestamp IS NOT NULL
        THEN
            v_query := 'SELECT COUNT(*) 
                        FROM my_schema.' || p_table_name | '
                        WHERE t = TO_DATE(''' || p_timestamp ||''', ''DD.MM.YYYY HH24:MI:SS.SSSS'')';

            EXECUTE IMMEDIATE v_query INTO   v_count;
            
            IF v_count > 0
            THEN
                v_query := 'DELETE FROM my_schema.' || p_table_name || '
                            WHERE t = TO_DATE(''' || p_timestamp ||''', ''DD.MM.YYYY HH24:MI:SS.SSSS'')';

                EXECUTE IMMEDIATE v_query;
            ELSE
                RETURN 'NO RECORDS FOUND!';
            END IF;
        ELSE
            RETURN 'TIMESTAMP EMPTY!';
        END IF;
    ELSE
        RETURN 'TABLE NAME EMPTY!';
    END IF;
END;
...