【问题标题】:cursor in a trigger触发器中的光标
【发布时间】:2012-07-19 18:41:51
【问题描述】:

我有一个现有的表postn_matrix,其中包含员工列表和他们各自的计数。组织中的职位。

每当添加或删除用户的位置时,相应的计数都会通过此触发器反映在表中(VIA UPDATE)

现在,如果有一个新用户,他将在postn_matrix 中没有条目,所以我必须为他/她插入一条新记录(VIA INSERT)。这需要从 BASE TABLE 中引入。

更新似乎运行良好,但我无法将新用户引入表中。

我一直在尝试用光标处理这种情况。但它还没有任何帮助。 我希望一些专家可以向我展示光明.. :)。除了使用光标之外的任何其他建议将不胜感激

CREATE OR REPLACE TRIGGER TRIG1
BEFORE INSERT OR DELETE ON (BASETABLE)
FOR EACH ROW
DECLARE
  cursor c1 is
  select person_id 
  from postn_matrix;

  v_temp varchar2(15);
BEGIN
  IF INSERTING THEN
    open c1;    
    LOOP
      fetch c1 into v_temp;

      if v_temp!=:new.person_id THEN
        insert into POSTN_MATRIX (PERSON_ID)
        VALUES (:new.PERSON_ID);
      else
        UPDATE POSTN_MATRIX
        //this is working fine ;

      END IF;
    end loop;
    close c1;

END
/

【问题讨论】:

  • 我不明白。如果 BASETABLE 中有一条新记录,并且您已经知道 POSTN_MATRIX 中没有记录,那么为什么要循环遍历 POSTN_MATRIX 上的游标呢?只需插入一条新记录。
  • 请拿一本关于 SQL 的基础书籍阅读一下。您确实需要一个游标来执行此操作,此外,您的 SQL 通常不应包含 if then 语句。 SQL 是一种面向集合的语言。见codeproject.com/Articles/10144/SQL-as-a-set-oriented-language

标签: sql oracle triggers plsql cursor


【解决方案1】:

由于循环(缺少退出子句 - 希望您刚刚丢失了将其转换为问题的原因),您将尝试为 每个 插入一条记录到 pstn_matrix > 记录游标返回,是否有匹配的:new.person_id;如果匹配,您还将执行update。这可能不是您想要的,并且您可能会遇到约束违规等情况。您也没有设置您的计数器字段 - 如果该字段不可为空,则将出错。但是你还没有说你得到了什么错误,如果有的话。

如果您必须通过触发器执行此操作,那么您可以检查是否有新人所在的行:

DECLARE
  v_temp postn_matrix.person_id%TYPE;
BEGIN
  IF INSERTING THEN
    select max(person_id) into v_temp
    from postn_matrix
    where person_id = :new.person_id;

    if v_temp is null then
      -- no record found, so insert one
      insert into postn_matrix (person_id, position_count)
      values (:new.person_id, 1);
    else
      -- record exists, so update
      update postn_matrix ...
    end if;
  ...

...或使用merge

但我不喜欢这种模型,而且您正在设置潜在的数据差异与对基表的并发修改。尝试保持这样的计数并不一定像看起来那么简单。

我通常更愿意将其设为一个视图,它始终是最新的,并且不需要使事情复杂化的触发器:

create view postn_matrix as
  select person_id, count(*)
  from basetable
  group by person_id;

当然,我可能误解或过度简化了您的基表的功能以及您需要postn_matrix 的用途。即使作为一种观点,它似乎也有点微不足道。如果你有单独的 personperson_position 表,那么你可以添加一个外连接来查看没有职位的人:

create view postn_matrix as
  select p.person_id, count(pp.position_id)
  from person p
  left join person_position pp on pp.person_id = p.person_id
  group by p.person_id;

【讨论】:

  • 嗨,Alex,非常感谢您提供的信息。我很理解使用 max(person_id) 的含义。你能解释一下吗?
  • 通过使用 MAX,他确信 SELECT 总是准确地返回一行,从而避免了对异常处理程序的需要。
  • @MayankG - 它正在检查该:new.person_id 的记录是否存在。如果它只是select person_id into v_temp,那么如果没有现有记录,你会得到ORA-01403,如果有不止一个,你会得到ORA-02112。使用max() 意味着你总是得到一排;如果有任意数量的匹配记录,它将具有 ID,否则将为空。您也可以使用count() 并检查是否找到了零行或非零行,如果您觉得更清楚的话。
  • 嗨,Alex,它成功了,谢谢..抱歉回复晚了,因为是周末,所以不能早点 :)
猜你喜欢
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多