【问题标题】:what is the statement for "where" condtion in pl/sqlpl/sql 中“where”条件的语句是什么
【发布时间】:2014-05-19 17:25:25
【问题描述】:

我想创建一个触发器,在删除表客户端之前为每一行执行,我想做的是当有人试图删除一行时:

DELETE FROM Clients WHERE id=5 AND name = 'test';

我想在屏幕上打印一些东西,例如: “您删除了以下条件:id 为 5,名称为 test” 或者执行另一个具有相同条件的查询...

非常感谢任何形式的帮助

编辑

假设用户输入了以下查询:DELETE FROM Clients where name = 'test'

create or replace 
TRIGGER DELETECLIENT 
BEFORE DELETE ON CLIENTS
DECLARE 
pragma autonomous_transaction;
name1 clients.name%Type; 
BEGIN
  select name into name1 from clients where  name = %I want here the name in the user query %;   
  IF name1 != null THEN 
    DELETE FROM clients WHERE name = name1;
    commit;
  END IF; 
END; 

我测试过的:

我尝试添加 :old.name 和 :new.name ,但是当我的数据库中不存在该行时这不起作用

PS:我这样做只是为了教育目的,我知道脚本没有意义。我只是想知道如何完成以下任务:获取查询中 WHERE 之后键入的参数

【问题讨论】:

  • 标题与问题有什么关系?在任何 PL/SQL 中“显示”一条消息实际上是没有意义的,因为您不能假设客户端会实际显示它。你的意思是你想为某些值引发异常,并做其他事情 - '执行查询'!? - 否则?
  • PL/SQL 不会“在屏幕上打印”。
  • @AlexPoole 是的,我想这样做:raise_application_error(-20050, 'bla bla');我知道它取消了查询,但没关系
  • 所以……我还是没看懂标题,你想知道if ... then在PL/SQL中是如何工作的吗?到目前为止,您有什么触发代码 - 请将您当前的版本添加到问题中。
  • @AlexPoole 请检查编辑

标签: sql oracle triggers sqlplus plsqldeveloper


【解决方案1】:

correlation names and pseudorecords 代表,即默认情况下:old:new,只对行级触发器有意义:

注意:
本主题仅适用于在行级触发的触发器,即行​​级简单 DML 触发器和具有行级时序点部分的复合 DML 触发器。

您不能在语句级触发器中引用这些,只有:olddelete 触发器中才有意义。另一方面,即使没有数据受到影响,语句级触发器也会触发,而在您的示例中,如果没有数据被删除,则不会触发行级触发器 - 因为表中没有匹配的行。 (这也适用于视图的instead of 触发器,以防您想知道这是否是一种解决方法)。

所以基本上你不能做你正在尝试的事情 - 有条件地决定是否从另一个表中删除 - 从触发器。触发器很少是正确的答案。对于您的“如果它在我的表上不存在我应该尝试在其他站点上找到它并删除它”的场景,您可以尝试在本地删除一行,测试它是否做了任何事情,然后决定从远程删除表如果没有。在一个简单的 PL/SQL 块中:

create procedure delete_client(p_name clients.name%type) as
begin
  delete from clients where name = p_name;
  if sql%rowcount = 0 then
    delete from clients@site2 where name = p_name;
  end if;
end delete_client;
/

而不是直接从表中删除,而是让每个人都调用该过程。假设您从一些数据开始:

select * from clients;

        ID NAME     
---------- ----------
         1 Joe        
         2 Anna       

select * from clients@site2;

        ID NAME     
---------- ----------
         1 Joe        
         3 Max        

然后调用两个名称的过程:

exec delete_client('Joe');
exec delete_client('Max');

...已适当地删除本地和远程记录:

select * from clients;

        ID NAME     
---------- ----------
         2 Anna       

select * from clients@site2;

        ID NAME     
---------- ----------
         1 Joe        

Joe 仅从本地模式中删除,尽管两者都存在; Max 在本地不存在,因此已从远程架构中删除。

不一定是程序;如果您通过 JDBC 等进行删除,您可以测试 execute() 调用的结果以查看有多少行受到影响,这就是 sql%rowcount 所做的一切,应用程序代码可以决定是否执行第二个 @ 987654335@.

但是通过一个过程(可能在一个包中)你可以授予execute,并从用户那里删除delete权限,所以他们不能绕过这个检查并直接做delete from clients where ...


如果您真的想要一些“显示”输出用于测试目的:

create procedure delete_client(p_name clients.name%type) as
begin
  delete from clients where name = p_name;
  if sql%rowcount > 0 then
    dbms_output.put_line('Deleted ' || sql%rowcount
      || ' rows from local schema for "' || p_name || '"');
  else
    delete from clients@site2 where name = p_name;
    if sql%rowcount > 0 then
      dbms_output.put_line('Deleted ' || sql%rowcount
        || ' rows from remote schema for "' || p_name || '"');
    else
      dbms_output.put_line('No rows deleted on local or remote schema for "'
        || p_name || '"');
    end if;
  end if;
end delete_client;
/

set serveroutput on
exec delete_client('Joe');

anonymous block completed
Deleted 1 rows from local schema for "Joe"

exec delete_client('Max');

anonymous block completed
Deleted 1 rows from remote schema for "Max"

exec delete_client('Fred');

anonymous block completed
No rows deleted on local or remote schema for "Fred"

但是你不应该假设任何调用你的过程的人都会打开serveroutput,或者甚至使用能够消费dbms_output消息的客户端。

【讨论】:

  • 非常感谢您的帮助,这正是我想要做的
猜你喜欢
  • 1970-01-01
  • 2022-01-14
  • 2013-03-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 2011-05-28
  • 2013-06-14
  • 2011-06-05
相关资源
最近更新 更多