使用 `getclobval()` 执行 oracle 程序时出现“无效字符错误”

Posted

技术标签:

【中文标题】使用 `getclobval()` 执行 oracle 程序时出现“无效字符错误”【英文标题】:`Invalid Character Error `while executing oracle procedure using `getclobval()` 【发布时间】:2021-01-23 03:52:15 【问题描述】:

以下过程在 ctrll + S 上成功编译(显示 VALID),但在执行时抛出错误:Invalid character error 同时在 SQL DEVELOPER 上执行此 procedure。 我没有看到任何我有无效字符的地方。

以下是创建表和插入值的代码:-

 CREATE TABLE tempt( "set" VARCHAR2(1), "level" VARCHAR2(1), category VARCHAR2(3), value INT );

INSERT INTO tempt
SELECT 'A', 'Z', 'ABC', 847549 FROM dual UNION ALL
SELECT 'A', 'Y', 'ABC', 955808 FROM dual UNION ALL
SELECT 'A', 'X', 'ABC', 983462 FROM dual UNION ALL
SELECT 'A', 'Z', 'GHI', 762369 FROM dual UNION ALL
SELECT 'A', 'Y', 'DEF', 615863 FROM dual UNION ALL
SELECT 'A', 'X', 'DEF', 474257 FROM dual UNION ALL
SELECT 'B', 'Z', 'ABC', 959843 FROM dual UNION ALL
SELECT 'B', 'Y', 'ABC', 821704 FROM dual UNION ALL
SELECT 'B', 'X', 'ABC', 377211 FROM dual UNION ALL
SELECT 'B', 'Z', 'DEF', 945053 FROM dual UNION ALL
SELECT 'B', 'Y', 'DEF', 919120 FROM dual UNION ALL
SELECT 'B', 'Y', 'ABC', 821704 FROM dual UNION ALL
SELECT 'C', 'X', 'ABC', 377211 FROM dual UNION ALL
SELECT 'C', 'Z', 'DEF', 945053 FROM dual UNION ALL
SELECT 'C', 'Y', 'DEF', 919120 FROM dual UNION ALL
SELECT 'D', 'X', 'ABC', 377211 FROM dual UNION ALL
SELECT 'D', 'Z', 'DEF', 945053 FROM dual UNION ALL
SELECT 'D', 'Y', 'GHI', 919120 FROM dual UNION ALL
SELECT 'E', 'X', 'ABC', 377211 FROM dual UNION ALL
SELECT 'E', 'Z', 'DEF', 945053 FROM dual UNION ALL
SELECT 'E', 'Y', 'ABC', 919120 FROM dual UNION ALL
SELECT 'E', 'Z', 'ABC', 945053 FROM dual UNION ALL
SELECT 'E', 'Y', 'DEF', 919120 FROM dual UNION ALL
SELECT 'B', 'X', 'IJK', 326886 FROM dual

这是在 SQL Developer/DB 的过程窗口中运行的:-

CREATE OR REPLACE PROCEDURE "SCHEMA.pivot"(v_recordset out sys_refcursor)
AS
--v_recordset SYS_REFCURSOR;
  v_sql       long;
  v_cols_1    long;
  v_cols_2    clob; 

BEGIN
  SELECT LISTAGG( ''''||"level"||''' AS "'||"level"||'"' , ',' )
          WITHIN GROUP ( ORDER BY "level" DESC )
    INTO v_cols_1
    FROM (
          SELECT DISTINCT "level"
            FROM tempt
          );

SELECT DBMS_XMLGEN.CONVERT (
          RTRIM (
           XMLAGG (XMLELEMENT (
                        e,
                          'MAX(CASE WHEN CATEGORY = '
                      || CHR (39)
                       || CATEGORY
                       || CHR (39)
                       || ' THEN '
                      || CHR (39)
                      || "level"
                       || CHR (39)
                      || ' END) AS '
                       || "level"
                      || '_'
                       || CATEGORY
                      || '',
                       ',')
                    ORDER BY 1 DESC).EXTRACT ('//text()').getclobval (),
           ','))
    INTO v_cols_2
   FROM (SELECT DISTINCT "level", CATEGORY
          FROM tempt);
                      

  v_sql :=
  'SELECT "set", ('|| v_cols_2 ||')
     FROM
     (
      SELECT *
        FROM tempt
           PIVOT
           (
            MAX(value) FOR "level" IN ( '|| v_cols_1 ||' )
           )
          )
          GROUP BY "set"
          ORDER BY "set"'; 
      v_sql := REPLACE (v_sql, ''', CHR (39));
      DBMS_OUTPUT.PUT_LINE(v_sql);
       
      OPEN v_recordset FOR v_sql;
 end pivot;

编辑 1:我运行了答案中提供的查询,尽管编译成功我得到了 Invalid Character 错误:-

00911. 00000 - "invalid character" *Cause: identifiers may not start with any ASCII character other than letters and numbers. $#_ are also allowed after the first character. Identifiers enclosed by doublequotes may contain any character other than a doublequote. Alternative quotes (q'#...#') cannot use spaces, tabs, or carriage returns as delimiters. For all other contexts, consult the SQL Language Reference Manual. 我看过其他有相同问题的帖子,并尝试了所有方法,但似乎没有解决问题。它显示的错误行是OPEN v_recordset FOR v_sql;

【问题讨论】:

【参考方案1】:

应该是

SQL> CREATE OR REPLACE PROCEDURE pivot (v_recordset OUT SYS_REFCURSOR)
  2  AS
  3     --v_recordset SYS_REFCURSOR;
  4     v_sql     LONG;
  5     v_cols_1  LONG;
  6     v_cols_2  CLOB;
  7  BEGIN
  8     SELECT LISTAGG ('''' || "level" || ''' AS "' || "level" || '"', ',')
  9               WITHIN GROUP (ORDER BY "level" DESC)
 10       INTO v_cols_1
 11       FROM (SELECT DISTINCT "level"
 12               FROM tempt);
 13
 14     SELECT DBMS_XMLGEN.CONVERT (
 15               RTRIM (
 16                  XMLAGG (XMLELEMENT (
 17                             e,
 18                                'MAX(CASE WHEN CATEGORY = '
 19                             || CHR (39)
 20                             || CATEGORY
 21                             || CHR (39)
 22                             || ' THEN '
 23                             || CHR (39)
 24                             || "level"
 25                             || CHR (39)
 26                             || ' END) AS '
 27                             || "level"
 28                             || '_'
 29                             || CATEGORY
 30                             || '',
 31                             ',')
 32                          ORDER BY 1 DESC).EXTRACT ('//text()').getclobval (),
 33                  ','))
 34       INTO v_cols_2
 35       FROM (SELECT DISTINCT "level", CATEGORY
 36               FROM tempt);
 37
 38     v_sql := 'SELECT "set", ' || v_cols_2 || '
 39       FROM
 40       (
 41        SELECT *
 42          FROM tempt
 43             PIVOT
 44             (
 45              MAX(value) FOR "level" IN ( ' || v_cols_1 || ' )
 46             )
 47            )
 48            GROUP BY "set"
 49            ORDER BY "set"';
 50     v_sql := REPLACE (v_sql, ''', CHR (39));
 51     DBMS_OUTPUT.PUT_LINE (v_sql);
 52
 53     OPEN v_recordset FOR v_sql;
 54  END pivot;
 55  /

Procedure created.

SQL>

测试:

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  2     l_rc  SYS_REFCURSOR;
  3  BEGIN
  4     pivot (l_rc);
  5  END;
  6  /
SELECT "set", MAX(CASE WHEN CATEGORY = 'GHI' THEN 'Y' END) AS Y_GHI,MAX(CASE
WHEN CATEGORY = 'ABC' THEN 'Y' END) AS Y_ABC,MAX(CASE WHEN CATEGORY = 'ABC' THEN
'Z' END) AS Z_ABC,MAX(CASE WHEN CATEGORY = 'DEF' THEN 'Z' END) AS Z_DEF,MAX(CASE
WHEN CATEGORY = 'IJK' THEN 'X' END) AS X_IJK,MAX(CASE WHEN CATEGORY = 'GHI' THEN
'Z' END) AS Z_GHI,MAX(CASE WHEN CATEGORY = 'DEF' THEN 'X' END) AS X_DEF,MAX(CASE
WHEN CATEGORY = 'ABC' THEN 'X' END) AS X_ABC,MAX(CASE WHEN CATEGORY = 'DEF' THEN
'Y' END) AS Y_DEF
     FROM
     (
      SELECT *
        FROM tempt

PIVOT
           (
            MAX(value) FOR "level" IN ( 'Z' AS "Z",'Y' AS
"Y",'X' AS "X" )
           )
          )
          GROUP BY "set"

ORDER BY "set"

PL/SQL procedure successfully completed.

SQL>

运行生成的查询会产生以下结果(截断):

SQL> SELECT "set", MAX(CASE WHEN CATEGORY = 'GHI  <snip>
ORY = 'DEF' THEN 'Z' END) AS Z_DEF,MAX(CASE WHEN  <snip>
(CASE WHEN CATEGORY = 'ABC' THEN 'X' END) AS X_A  <snip>
  2       FROM
  3       (
  4        SELECT *
  5          FROM tempt
  6             PIVOT
  7             (
  8              MAX(value) FOR "level" IN ( 'Z'
  9             )
 10            )
 11            GROUP BY "set"
 12            ORDER BY "set"
 13  /

s Y Y Z Z X Z X X Y
- - - - - - - - - -
A Y Y Z Z   Z X X Y
B   Y Z Z X   X X Y
C   Y Z Z     X X Y
D Y Y Z Z   Z X X Y
E   Y Z Z     X X Y

SQL>

附: 忘了说:真的,真的REALLY在双引号下使用小写字母命名列是个坏主意。

【讨论】:

不幸的是,这是我们表格中给出的列名,我知道这些是保留关键字 你能告诉我你在哪里跑SQL&gt; SET SERVEROUTPUT ON SQL&gt; DECLARE l_rc SYS_REFCURSOR; BEGIN pivot (l_rc); END; / 是的,PL/SQL 块已编译,但我使用了您在 Testing window 上提供的相同执行语句 .. 它不起作用..(它的 SQL*Plus 是有意义的) .我在proc窗口上使用了内置的run按钮,它给出了invalid character错误 我不知道,我不知道“proc 窗口上的内置 RUN 按钮”。过程及其查询可以正常工作 - 如图所示。 *Cause: identifiers may not start with any ASCII character other than letters and numbers. $#_ are also allowed after the first character. Identifiers enclosed by doublequotes may contain any character other than a doublequote. Alternative quotes (q'#...#') cannot use spaces, tabs, or carriage returns as delimiters. For all other contexts, consult the SQL Language Reference Manual.

以上是关于使用 `getclobval()` 执行 oracle 程序时出现“无效字符错误”的主要内容,如果未能解决你的问题,请参考以下文章

[ORACE] Oracle trace 之二10046事件

Navicat Oracal

orac

orace owi??????

orace学习操作

Orac and Medians