`Invalid Character Error `while executing oracle procedure using `getclobval()`
Asked Answered
D

1

0

The following procedure compiles successfully on ctrll + S (shows VALID) but on execution throws the error : Invalid character error while executing this procedure on SQL DEVELOPER. I don't see anywhere I have a invalid character.

The following is the code to Create table and insert values:-

 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

This is run inside the procedure window on the the SQL Developer/DB viz:-

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;

EDIT 1 : I ran the query provided in the answer ,though compiled sucessfully I get a Invalid Character Error :-

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. I have seen the other posts with same question and tried out everything but doesnt seem to fix the issue. Line it shows for the error is OPEN v_recordset FOR v_sql;

Danielson answered 8/10, 2020 at 6:14 Comment(0)
U
0

Should be

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>

Testing:

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>

Running the resulting query produces the following result (snipped):

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>

P.S. Forgot to say: really, really, REALLY bad idea naming column using lower case under double quotes.

Uralic answered 8/10, 2020 at 6:49 Comment(5)
unfortunately thats the name of columns given in our tables,I understand those are reserved key wordsDanielson
Could you tell me where have you run SQL> SET SERVEROUTPUT ON SQL> DECLARE l_rc SYS_REFCURSOR; BEGIN pivot (l_rc); END; /Danielson
Yes the PL/SQL block got compiled, but i used the same execution statements you have provided on Testing window .. it doesn't work..(which makes sense as its SQL*Plus).I used the inbuilt run button on proc window, it gives invalid character errorDanielson
I wouldn't know, I don't know the "inbuilt RUN button on proc window". Procedure, as well as its query, work correctly - as demonstrated.Uralic
*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.Danielson

© 2022 - 2024 — McMap. All rights reserved.