PL SQL - 使用动态 SQL 生成删除语句

Posted

技术标签:

【中文标题】PL SQL - 使用动态 SQL 生成删除语句【英文标题】:PL SQL- Using Dynamic SQL to Generate Delete Statements 【发布时间】:2015-11-03 01:05:33 【问题描述】:

我想使用 PL SQL 创建一个存储过程,它允许我查找包含特定列的所有表,然后从那些表中删除在该列中具有特定值的记录。

例如,我想查找所有具有“年”列的表,然后从所有具有“2012”年的表中删除所有记录(今年将是执行时输入的参数)

我在这方面的尝试是创建一个存储过程,使用游标获取所有具有“年”列的表,然后使用动态 SQL 循环遍历该游标,这将生成我的删除语句,我可以执行。

CREATE OR REPLACE PROCEDURE year_deletion
(
p_year  NUMBER --Input of the year for records to be deleted 
)
IS
CURSOR c1 --Cursor that will find all tables that have the YEAR column
IS
    SELECT owner, table_name 
    FROM all_tab_columns 
    WHERE column_name = 'YEAR'
    AND owner = 'GTP';

BEGIN
FOR i IN c1 LOOP    --Loop through all of the tables that the cursor found, generate a SQL statement for each table that will delete all of the records that have the year of p_year
   EXECUTE IMMEDIATE ('SELECT * FROM' ||i.table_name|| 'WHERE YEAR = '||p_year||';'); 
END LOOP;

END;

免责声明:出于测试目的,我使用 Select * From 而不是 DELETE * From,当此过程正确执行时,我将更改它。

到目前为止,这个存储过程可以正确编译,但在执行过程中给我一个错误,即预期有 FROM 关键字但未找到。这是为我的目的使用的最佳方法吗?

【问题讨论】:

您需要在 FROM 之后添加空格,所以应该是 FROM ' 而不是 ...FROM'我> || operator 会将 i.table_name 粘贴到 FROM 上,然后你就会有一个 FROMi.table_name 这样的词,这当然不是编译器要找的 另外你必须在 'WHERE YEAR =... 中添加一个空格应该是 ' WHERE YEAR =' 您也可以在循环内添加一个异常块,在这种情况下至少打印错误。例如,如果您有一些表,其中 YEAR 是一个字符串并且具有字符串值,那么您的 sql 将失败,并且 lopp 将在该点停止。 【参考方案1】:

一定是这样的:

EXECUTE IMMEDIATE 'DELETE FROM ' ||i.table_name|| ' WHERE YEAR = :theYear' USING p_year; 

注意FROMWHERE 之前的空格。

您不能简单地将DELETE 替换为SELECT ... 进行测试,因为对于SELECT,您必须有一个INTO 子句。

你的整个过程可以是这样的

CREATE OR REPLACE PROCEDURE year_deletion(p_year IN NUMBER) IS

   CURSOR c1 IS
   SELECT owner, table_name 
   FROM all_tab_columns 
   WHERE column_name = 'YEAR'
      AND owner = 'GTP';

   res NUMBER;

BEGIN
   FOR i IN c1 LOOP
      EXECUTE IMMEDIATE 
         'SELECT COUNT(*) FROM ' ||i.table_name|| ' WHERE YEAR = :theYear' INTO res USING p_year;
      DBMS_OUTPUT.PUT_LINE (res ||' rows will be deleted from table '||i.table_name );
      EXECUTE IMMEDIATE 
         'DELETE FROM ' ||i.table_name|| ' WHERE YEAR = :theYear' USING p_year; 
   END LOOP;
END;

【讨论】:

【参考方案2】:
Hello you can try the below code. It will surely help you out.

CREATE OR REPLACE PROCEDURE year_deletion(
    p_year IN  NUMBER --Input of the year for records to be deleted
  )
IS
BEGIN
  FOR i IN (SELECT owner,
      table_name
    FROM all_tab_columns
    WHERE column_name = 'YEAR'
    AND owner         = 'GTP')
  LOOP --Loop through all of the tables that the cursor found, generate a SQL statement for each table that will delete all of the records that have the year of p_year
    EXECUTE IMMEDIATE 'DELETE FROM ' ||i.table_name|| ' WHERE YEAR = '||p_year;
  END LOOP;
END;

【讨论】:

以上是关于PL SQL - 使用动态 SQL 生成删除语句的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL开发中动态SQL的使用方法

PL/SQLPL/SQL中动态执行SQL语句

Oracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置

Oracle_PL/SQL 动态sql

Oracle PL/SQL 动态 if 语句全局变量

Oracle pl sql 动态使用子句