【问题标题】:Oracle Trigger PLS-00103. Query with multiple rows in temporal variableOracle 触发器 PLS-00103。查询时态变量中的多行
【发布时间】:2021-01-23 02:46:28
【问题描述】:

我正在尝试编写一个触发器,当有人尝试对尚未购买的产品进行评分时会引发错误。我想出了一个查询来获取客户的购买历史:

SELECT nref 
FROM CartClient a 
INNER JOIN PaidCart b 
     ON a.idpurchase = b.idpurchase
INNER JOIN CartDetails c  
     ON b.idpurchase = c.idpurchase 
WHERE a.Id = '12345672X'

效果很好。

所以下一个触发器应该检查新评级的产品 (:new.NRef) 是否未被购买,即不是最后一个查询结果的一部分 (NOT IN)。

CREATE OR REPLACE TRIGGER cant_rate
BEFORE INSERT ON Rating
FOR EACH ROW   
    BEGIN
        IF (:new.NRef NOT IN (SELECT nref FROM CartClient a 
                                   INNER JOIN PaidCart b 
                                      ON a.idpurchase = b.idpurchase
                                   INNER JOIN CartDetails c  
                                      ON b.idpurchase = c.idpurchase 
                                   WHERE a.Id =:new.Id)) THEN
            RAISE_APPLICATION_ERROR(-20603,'Cant rate a not bought product');
        END IF;
    END;

我得到错误:

“PLS-00103:在期待其中之一时遇到符号“INNER”。

我尝试使用 SELECT INTO 将查询结果存储在一个时间变量中。但是,这是一个多行结果。我能做什么?

【问题讨论】:

  • 什么是完整的错误信息?
  • 如果您使用的是 11g,11G Forms 不支持 ANSI 标准连接语法。
  • 表格? @eshirvana 是什么让您认为它与 Forms 相关?
  • @Littlefoot 只是猜测,根据错误信息
  • 嗯,我宁愿以我看到的代码为基础——上面写着create or replace trigger ...,这意味着它存储在数据库中;它不是表单触发器,所以......我想说你的反对在这种情况下是错误的,@eshirvana。

标签: sql oracle triggers


【解决方案1】:

这样的方法怎么样?

CREATE OR REPLACE TRIGGER cant_rate
  BEFORE INSERT ON Rating
  FOR EACH ROW   
DECLARE
  l_exists NUMBER(1) := 0;
BEGIN
  SELECT MAX(1)
    INTO l_exists
    FROM dual
    WHERE EXISTS (SELECT nref FROM CartClient A 
                  INNER JOIN PaidCart b 
                     ON A.idpurchase = b.idpurchase
                  INNER JOIN CartDetails C  
                     ON b.idpurchase = C.idpurchase 
                  WHERE A.ID = :NEW.ID
                    AND a.nref = :NEW.nref           --> is it "a.nref"?
                 );
  IF l_exists = 0 THEN
     RAISE_APPLICATION_ERROR(-20603,'Cant rate a not bought product');
  END IF;
END;

注意备注“它是 a.nref 吗?” - 你从来没有说过哪个表拥有 nref 列,所以我假设它是 cartclient;如有必要,请修改它。


在您的尝试中:如果您在 SQL*Plus 或 SQL Developer 中执行它,您会在 IF 中看到有关子查询的消息;像这样:

LINE/COL  ERROR
--------- -------------------------------------------------------------
2/3       PL/SQL: Statement ignored
2/21      PLS-00405: subquery not allowed in this context

所以,不——你不能那样做。

【讨论】:

    【解决方案2】:

    您可能没有得到实际错误:PLS-00405 subquery not allowed in this context。

    简单的愚蠢测试:

    BEGIN
       IF 1 NOT IN ( SELECT 2 FROM DUAL )
       THEN
          NULL;
       END IF;
    END;
    /
    

    您可以通过这种方式或类似方式调整触发器:

    CREATE OR REPLACE TRIGGER cant_rate
    BEFORE INSERT ON Rating
    FOR EACH ROW
    DECLARE
       l_test   PLS_INTEGER;
    BEGIN
    
       SELECT CASE
                WHEN :new.NRef NOT IN ( SELECT nref
                                          FROM CartClient a 
                                          INNER JOIN PaidCart b 
                                             ON a.idpurchase = b.idpurchase
                                          INNER JOIN CartDetails c  
                                             ON b.idpurchase = c.idpurchase 
                                          WHERE a.Id = :new.Id
                                      )
                THEN 1
                ELSE 0
               END
        INTO l_test;
        FROM DUAL;
    
       IF l_test = 1
       THEN
        ...
        
       END IF;
    END;
    /
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多