将 table 名称和时间戳变量传递给 PL/SQL

Pass a table name and time stamp variable to a PL/SQL

我正在 SQL 开发人员中编写下面的 PL/SQL 代码,以从 table 中删除数据,并在 where 条件中包含时间戳列。我如何修改此代码以根据我想要从中删除数据的 table 和时间记录将 table 名称和时间戳值传递给我想要的值并创建一个存储过程重复使用。

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;

我无法对其进行测试,但您可以创建一个将 table 名称和时间戳作为参数的函数。 只要您想删除具有给定时间戳的每条记录,您就不需要为每条记录循环。 这个函数应该只是一个例子。

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;

如前所述,使匿名存储过程适应存储过程需要将其转换为动态 SQL。总是更难。并受到SQL注射。为此,您应该验证字符串替换参数。我还有一些其他更改:

  • 将所需的作为时间戳而不是字符串传递,这 allows/forces 调用例程以确定格式和必要的转换,如果 任何。
  • 也为列名添加了一个参数。这释放命名列 从程序的要求。
  • 无需清点剩余物品。你的循环过程直到 该值达到 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;

参见example:在示例中,我将每次迭代删除的行数从 100000 减少到 20。另外的增强功能是将每次迭代的行数作为参数传递。