oracle PL/SQL编程:使用块标签区分变量

ocebsuys  于 2023-03-29  发布在  Oracle
关注(0)|答案(3)|浏览(151)

我已经写了下面的代码行,并执行它从PL/SQL开发工具相同。
我还在Oracle 11 g数据库中创建了HR Schema。

代码

CREATE TABLE employees2 AS SELECT last_name FROM employees;
<<MAIN>>
DECLARE
last_name VARCHAR2(10) := 'King';
my_last_name VARCHAR2(10) := 'King';
BEGIN

-- Deletes everyone, because both LAST_NAMEs refer to the column
DELETE FROM employees2 WHERE last_name = last_name;
dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.');
ROLLBACK;

-- OK, column and variable have different names
DELETE FROM employees2 WHERE last_name = my_last_name;
dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.');
ROLLBACK;

-- OK, block name specifies that 2nd LAST_NAME is a variable
DELETE FROM employees2 WHERE last_name = main.last_name;
dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows.');
ROLLBACK;
END;
/
DROP TABLE employees2;

但是在执行第一个declare语句时,它会抛出如下错误

ORA-06550: line 4, column 0:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

   * & = - + ; < / > at in is mod remainder not rem
   <an exponent (**)> <> or != or ~= >= <= <> and or like like2
   like4 likec between || multiset member submultiset

请指导我,因为我是PL/SQL的新手,目前正在自学。

lhcgjxsq

lhcgjxsq1#

这是PL/SQL Developer词法分析器或解析器的一个bug。您可以通过将整个块包含在另一个begin ... end;中来解决它。
SQL窗口可以同时使用SQL和PL/SQL,但是这两种语句类型有不同的语法。编辑器窗口不需要完整的解析器。但是它必须对语句有足够的了解,以便知道一个语句何时结束,另一个语句何时开始。有很多方法可以启动SQL语句,而很少有方法可以启动PL/SQL块。代码可能使用如下的分类算法:“如果它以beginend开头,则是PL/SQL,否则是SQL”。程序员可能忘记了PL/SQL可以以标签开始。由于解析器认为它是SQL语句,因此它在第一个分号处停止。
您可以在下面的错误和突出显示中看到,它基于第一个分号分割语句:

Frank施密特的想法很好,通常可以解决这类问题,但在这种情况下,命令窗口和高亮显示整个表达式都不能解决问题。
唯一的解决办法似乎是添加一个额外的beginend块,如下所示:

--Add extra begin/end to work around PL/SQL Developer parser bug.
begin
    <<main>>
    declare
        v_test number := 1;
    begin
        main.v_test := 1;
    end;
end;
/
xtupzzrd

xtupzzrd2#

你的代码很好,所以我猜这是客户端的问题。
PL/SQL Developer有不同类型的窗口-对于这种查询,您应该使用“命令窗口”(本质上是SQL/Plus提示符)。
如果运行整个脚本不起作用,请尝试单独运行每个语句(在“SQL窗口”中,您可以选择一个代码块并仅运行所选内容)。

prdp8dxp

prdp8dxp3#

这条评论是正确的。使用命令窗口,而不是SQL窗口。如果你去掉SQL*PLUS的东西,比如SET SERVEROUTPUT...等,你也可以使用测试窗口来练习脚本。这允许一种调试,尽管我不太清楚如何在主脚本本身中放置断点-只称为对象。
因此,对于一个获取模式中所有物化视图并重新编译无效视图的大型示例,刷新它们并安排它们进行夜间刷新。

请注意,SQL PLUS命令行工具在此处针对测试窗口关闭,但不需要针对PL/SQL开发人员命令窗口禁用...:

*/*SET SERVEROUTPUT ON SIZE UNLIMITED
\* NB - change the log file name in the PDC file*\
--SPOOL "Script_Compile_Refresh_All_KDOT_BLP_MViews-20230327.log"*

--SET ECHO OFF
--SET TERMOUT OFF

--WHENEVER SQLERROR CONTINUE

*/
BEGIN

<<MAIN>>
DECLARE
         
v_MVN1 VARCHAR2(32767);
v_X1 VARCHAR2(32767);
     
BEGIN

     <<COMPILEMVS>>   
      DECLARE
          CURSOR curMVCompileNames IS 
        SELECT umv.MVIEW_NAME     
        FROM ALL_MVIEWS umv
        WHERE umv.owner =  USER
              and UPPER(umv.COMPILE_STATE ) = 'NEEDS_COMPILE';
       BEGIN   
          DBMS_OUTPUT.PUT_LINE(q'[Get the MV names where compile state = 'NEEDS_COMPILE']');
          OPEN curMVCompileNames;
          FETCH  curMVCompileNames 
            INTO v_MVN1;
             
             IF NOT (V_MVN1 IS NULL) THEN
               
                 
                  WHILE (curMVCompileNames%FOUND) LOOP
                    BEGIN
                           
                     DBMS_OUTPUT.PUT_LINE(q'[RECOMPILING INVALID MVIEW ]' || v_MVN1 );
                      v_X1 := q'[ALTER MATERIALIZED VIEW ]' ||'  ' ||  V_MVN1 || '  ' || q'[ COMPILE]' ||'  ';
                      DBMS_OUTPUT.PUT_LINE(q'[EXECUTING IMMEDIATE>>> ]' ||v_X1);
                      
                      EXECUTE IMMEDIATE v_X1;
                      
                    EXCEPTION     
                    WHEN OTHERS THEN 
                        BEGIN
                        DBMS_OUTPUT.PUT_LINE(q'[COMMAND FAILED ]' || V_X1);
                        CONTINUE;
                        END;        
                    END;
                    
                    FETCH curMVCompileNames
                      INTO v_MVN1;
                  END LOOP;
           END IF;

          CLOSE curMVCompileNames;
         
     END COMPILEMVS;

 
    <<REFRESHMVS>>
      DECLARE
      CURSOR curMVValidNameCSV IS 
      SELECT LISTAGG( umv.MVIEW_NAME , q'[, ]' ) 
      WITHIN GROUP (
      ORDER BY CASE
                    WHEN UPPER(umv.mview_name) = 'MV_LATEST_INSPECTION' THEN
                     '01 - '
                    ELSE
                     CASE
                       WHEN UPPER(umv.mview_name) LIKE 'MV_LATEST%' THEN
                        '02 - ' || UPPER(umv.mview_name)
                       ELSE
                        '03 - ' || UPPER(umv.mview_name)
                     END
                  END) AS VALID_MVIEW_NAMES
      FROM USER_MVIEWS umv
      WHERE umv.owner = USER
            and UPPER(umv.COMPILE_STATE) = 'VALID';
      BEGIN   

        v_MVN1 := '';
          OPEN curMVValidNameCSV;
          FETCH  curMVValidNameCSV 
            INTO v_MVN1;                
               IF NOT (V_MVN1 IS NULL) THEN   
                       BEGIN
                          
                          DBMS_OUTPUT.PUT_LINE(q'[VALID MV Names: ]' || v_MVN1 );
                          /*  -- refresh them all right now */
                          DBMS_MVIEW.REFRESH(list=> v_MVN1 , purge_option=> 2, atomic_refresh=>  false, parallelism=> 4, method=> 'c?');
                               
                        EXCEPTION     
                          WHEN OTHERS THEN 
                              BEGIN
                                DBMS_OUTPUT.PUT_LINE(q'[REFRESH COMMAND FAILED for MV LIST: ]' || v_MVN1);
                                RAISE;
                              END;        
                       END;
               END IF;      
          CLOSE curMVValidNameCSV;
      END REFRESHMVS;

   <<SCHEDULEMVS>>
      DECLARE       
          CURSOR curMVValidNames IS 
          SELECT  umv.MVIEW_NAME               
            FROM USER_MVIEWS umv
           WHERE umv.owner = USER
             and UPPER(umv.COMPILE_STATE) = 'VALID'
             ORDER BY 
             CASE WHEN UPPER(umv.mview_name) = 'MV_LATEST_INSPECTION'
             THEN
                   '01 - '
                  ELSE
                   CASE
                     WHEN UPPER(umv.mview_name) LIKE 'MV_LATEST%' THEN
                      '02 - ' || UPPER(umv.mview_name)
                     ELSE
                      '03 - ' || UPPER(umv.mview_name)
                   END
                END;               
        BEGIN              
              V_MVN1 :='';

            OPEN curMVValidNames;
            FETCH  curMVValidNames 
              INTO v_MVN1;
                  
            IF NOT (V_MVN1 IS NULL) THEN     
                      
                WHILE (curMVValidNames%FOUND) LOOP
                    BEGIN                      
                      /*   -- set the schedule to refresh each one on a schedule tomorrow at 3AM and every night thereafter at 3AM   */       
                      v_X1 := q'[ALTER MATERIALIZED VIEW ]' ||    V_MVN1 ||  q'[ REFRESH COMPLETE START WITH TRUNC(SYSDATE+1) + 3/24  NEXT (SYSDATE+1) + 3/24 ]';
                      DBMS_OUTPUT.PUT_LINE(q'[EXECUTING IMMEDIATE >>> ]' ||v_X1); 
                      EXECUTE IMMEDIATE v_X1;                                   
                      
                    EXCEPTION     
                      WHEN OTHERS THEN 
                          BEGIN
                            DBMS_OUTPUT.PUT_LINE(q'[ALTER COMMAND FAILED: ]' || v_X1);
                            RAISE;
                       END;    
                    END;
                    FETCH curMVValidNames
                        INTO v_MVN1;
              END LOOP;              
         END IF;
            CLOSE curMVValidNames;
      END SCHEDULEMVS;
EXCEPTION
  WHEN OTHERS THEN RAISE;
END MAIN;
END;

/*/

spool off*/

相关问题