sql >> Base de Datos >  >> RDS >> Oracle

ORA-22905:al consultar un tipo de tabla con una declaración de selección

Es posible consultar tipos de tablas en PL/SQL, pero solo tablas anidadas y varrays cuyos tipos se declaran a nivel de esquema, es decir, fuera de PL/SQL.

El error

ORA-22905:no se puede acceder a filas desde un elemento de tabla no anidado

significa que está intentando consultar desde un tipo de tabla no compatible. Tu tipo type_tab_AB es una matriz asociativa, debido al INDEX BY BINARY_INTEGER cláusula. Eliminar el INDEX BY BINARY_INTEGER cláusula para hacer su type_tab_AB un tipo de tabla anidada. (Las matrices Varray también funcionarían aquí, pero no recomendaría usarlas a menos que conozca un límite superior para la cantidad de filas esperadas. Al declarar un tipo Varray, debe especificar la cantidad máxima de elementos, mientras que los tipos de tablas anidadas tienen no hay tal restricción.)

Después de realizar este cambio, es posible que su código aún no funcione. El siguiente error que puede recibir (vea la nota en la parte inferior si no lo hace) es

PLS-00642:tipos de colecciones locales no permitidos en sentencias SQL

Esto se debe a que el tipo que está seleccionando se declara dentro de PL/SQL. Debe declarar type_tab_AB y record_AB fuera de PL/SQL, usando CREATE TYPE ... .

El próximo problema que encuentre será debido a la palabra clave RECORD . Los tipos de registro solo se pueden crear dentro de PL/SQL, no se pueden crear a nivel de esquema. Cambiar RECORD a OBJECT para arreglar esto.

El último problema que encontrará es con SELECT t.AA, t.BB BULK COLLECT INTO tab_AB FROM ... declaración. Tal como está, esta consulta le dará el siguiente error:

PL/SQL:ORA-00947:no hay suficientes valores

Está seleccionando dos elementos de cada fila y está proporcionando solo una tabla para insertar los datos de forma masiva. Oracle no puede darse cuenta de que desea incluir los dos elementos en su record_AB tipo. Puede solucionar esto con bastante facilidad cambiando la consulta a SELECT record_AB(t.AA, t.BB) BULK COLLECT INTO tab_AB FROM ... .

En conjunto, estos cambios deberían solucionar el problema. Aquí hay un script SQL*Plus completo que crea una tabla de prueba con algunos datos de prueba y verifica que puede consultar el tipo de tabla:

CREATE TABLE some_table (AA VARCHAR2(16 BYTE), BB VARCHAR2(16 BYTE));

INSERT INTO some_table (AA, BB) VALUES ('aa 1', 'bb 1');
INSERT INTO some_table (AA, BB) VALUES ('aaaaaaaaaa 2', 'b 2');
INSERT INTO some_table (AA, BB) VALUES ('aaaaa 3', 'bbbbbbbbbbbbbb 3');
COMMIT;

VARIABLE curs REFCURSOR;

CREATE OR REPLACE TYPE record_AB AS OBJECT
   (
      AA    VARCHAR2 (16 BYTE),
      BB    VARCHAR2 (16 BYTE)
   );
/

CREATE OR REPLACE TYPE type_tab_AB IS TABLE OF record_AB;
/

DECLARE
  tab_AB   type_tab_AB;
BEGIN
  SELECT record_AB(t.AA, t.BB)
    BULK COLLECT INTO tab_AB 
    FROM some_table t;

  OPEN :curs FOR SELECT * FROM TABLE (tab_AB) ;
END;
/

PRINT :curs

He puesto el resultado de SELECT ing el contenido de tab_AB en un cursor y usó una variable de cursor SQL*Plus para listar su contenido. El resultado que obtengo cuando ejecuto el script en Oracle 11g XE, después de todos los mensajes 'Tipo creado' y 'Procedimiento PL/SQL completado con éxito', es el siguiente:

AA               BB
---------------- ----------------
aa 1             bb 1
aaaaaaaaaa 2     b 2
aaaaa 3          bbbbbbbbbbbbbb 3

NOTA: Para simplificar, supuse que el autor de la pregunta usa Oracle 11 o anterior. En Oracle 12, creo que puede usar tipos declarados en PL/SQL en una consulta SQL, por lo que es posible que no encuentre el error PLS-00642. No puedo decir qué otros cambios en mi respuesta también podrían ser necesarios para Oracle 12, ya que todavía tengo que usar Oracle 12.