Oracle - Ejecutar Funcion

 
Vista:

Ejecutar Funcion

Publicado por Alfredo (17 intervenciones) el 17/12/2008 00:59:37
Hola como están tengo un problema con un query dinamico , no se si yo estoy haciendo algo mal estoy trabajando con oracle 11g
mi bloque es el siguiente donde mando llamar a una funcion y me manda el siguiente error
me podrian ayudar
Gracias.

Error at line 1
ORA-06550: línea 15, columna 19:
PLS-00201: el identificador 'F_DROP_OBJECT' se debe declarar
ORA-06550: línea 15, columna 8:
PL/SQL: Statement ignored

declare
v_sDoctype VARCHAR2(10);
v_existe NUMBER := 0;
cnumber NUMBER;

begin
v_sDoctype := '134';
SELECT 1
INTO v_existe
FROM DUAL
WHERE EXISTS (SELECT OBJECT_NAME FROM
USER_OBJECTS WHERE OBJECT_NAME ='WEB_AGREGADOC134');
IF
v_existe = 1 THEN
cnumber := F_DROP_OBJECT(v_sDoctype);
END IF;
end;
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 17/12/2008 19:51:58
Hola, Alfredo.
Perdona, pero hay algo que no entiendo. Dices que estás intentando ejecutar un código dinámico, pero el bloque que nos indicas veo que es estático.

Con ese error el motor de B.D. te indica que no encuentra entre los objetos "visibles" para tu usuario ninguno llamado F_DROP_OBJECT.

Por favor, comprueba si ese objeto existe. Comprueba por favor si ese objeto (F_DROP_OBJECT) existe, y si el usuario con el que ejecutas el código anterior tiene permisos sobre ese objeto.

También te aconsejaría que pusieras en el bloque un tratamiento de errores, ya que al menos la sentencia "SELECT" puede lanzar varias excepciones. Quizá lo único que ocurre es que has escrito un ejemplo rápido para mostrarnos el problema, en ese caso ignora este comentario.

Un saludo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Alfredo (17 intervenciones) el 17/12/2008 20:07:18
Que tal Carlos , tienes razon puse un ejemplo algo apresurado , bueno el problema que tengo es el siguiente , de acuerdo a el siguiente store procedure , hago un barrido de varias tablas y armo un query para hacer una extraccion el codigo es el siguiente :

despues de hacer el barrido , pinto el resultado DBMS_OUTPUT.PUT_LINE(v_sql); y despues intento ejecutarlo con EXECUTE IMMEDIATE (v_sql); pero no pasa nada , no se si estoy haciendo algo mal en la sintaxis o no lo permite oracle , espero me puedas ayudar
gracias.

CREATE OR REPLACE procedure BNXAFILIACION.web_Ac_Obtienecampos2
(
v_iDocid IN NUMBER DEFAULT NULL ,
cv_1 OUT SYS_REFCURSOR
)
AS

v_tabla VARCHAR2(50);
v_sql VARCHAR2(5000);
v_resultado VARCHAR2(5000);
v_i NUMBER(3,0);
v_max NUMBER(3,0);
v_campos NVARCHAR2(250);
v_campos2 NVARCHAR2(250);

BEGIN

BEGIN
SELECT tabla
INTO v_tabla
FROM TiposDocumento a,DIGITALIZAMAIN b
WHERE b.doctype = a.TipoDocumentoID
AND b.docid = v_iDocid;

EXCEPTION
WHEN OTHERS THEN v_tabla := NULL;
END;

DBMS_OUTPUT.PUT_LINE(v_tabla);

IF v_tabla IS NULL OR v_tabla = '' THEN

OPEN cv_1 FOR
SELECT v_iDocid ,'Error, no existe el docid'
FROM DUAL ;

ELSE
BEGIN

SELECT MAX(CampoID) + 1
INTO v_max
FROM CatCamposDocumento
WHERE Tabla = v_tabla;

v_sql := '';
v_i := 1;

WHILE v_i < v_max
LOOP
BEGIN
SELECT NVL(v_sql, '') || 'select ' ||to_char(v_iDocid) ||' as Docid,Nombrecampo as Campo,
nvl((select to_char(' || NombreCampo || ' )from ' || Tabla || ' where Docid = '|| to_char(v_iDocid) ||'),'|| CHR(39)|| ' '
|| CHR(39) || ') as ' || 'Valor ,to_char(NVL(PermisoID, 0) ) as PermisoID, TipoDato, LongitudMax, LongitudMin,
Obligatorio,Mostrar, Mascara, Regla,accion,TipoDatoConsulta, condicion1,condicion2,condicion3,
tipoDatoCliente from CatCamposDocumento where CampoID=' || TO_CHAR(v_i) || ' and Tabla= ' || CHR(39) || v_tabla || CHR(39) || '
union all '
INTO v_sql
FROM CatCamposDocumento
WHERE Tabla = v_tabla
AND CampoID = v_i;
--and Obligatorio=1

v_i := v_i + 1;


END;
END LOOP;

BEGIN
v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 11)||';';
--OPEN cv_1 FOR SELECT v_sql FROM DUAL ;

DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE (v_sql);


EXCEPTION
WHEN OTHERS THEN

IF TO_CHAR(SQLCODE) = '-2260'
THEN
NULL;
END IF;

END;
END;
END IF;
END;

, ya que el mismo problema me pasa con comandos como DROP , ALTER etc... es por eso que hice la funcion

BNXAFILIACION.F_DROP_OBJECT(v_sDoctype); pero me marka el siguiente error

Error at line 1
ORA-06550: línea 15, columna 20:
PLS-00201: el identificador 'BNXAFILIACION.F_DROP_OBJECT' se debe declarar
ORA-06550: línea 15, columna 9:
PL/SQL: Statement ignored
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 18/12/2008 12:16:52
Hola, Alfredo.

Al ejecutar código de recuperación de datos (un SELECT) con EXECUTE IMMEDIATE se han de cumplir los mismos requisitos que si lo hicieras en código estático con un SELECT ... INTO, es decir, ha de recuperar una única fila (o ninguna si no hay datos). De otra manera provoca un error.

¿Por qué no está viendo ningún error?.
Tienes el siguiente manejador de errores:

EXCEPTION
WHEN OTHERS THEN

IF TO_CHAR(SQLCODE) = '-2260'
THEN
NULL;
END IF;

Lo que está haciendo es lo siguiente: si el sqlcode es -2260, no hace nada. Si no lo es, tampoco. Es decir, de manera efectiva está ignorando todos los errores que se produzcan, que es por lo que no te responde nada.
Si lo sustituyes por el siguiente:
EXCEPTION
WHEN OTHERS THEN

IF TO_CHAR(SQLCODE) = '-2260'
THEN
NULL;
ELSE
RAISE;
END IF;

Propagará todos los errores que no sean el -2260.

Por otra parte, indicarte que el manejador "WHEN OTHERS" debería utilizarse con mucha precaución, ya que como en este caso puede enmascarar otros errores.

Por otra parte y una vez que el programa te funcione, me parece que lo que estás haciendo en el bucle WHILE podrías reescribirlo en un bucle FOR o incluso no hacerlo en SQL dinámico, esto último sólo como hipótesis, ya que puede que tengas ciertos requerimientos que no conozco.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por alfredo (17 intervenciones) el 18/12/2008 17:10:01
voy a modificar los exception carlos , te agradezco y te aviso si funciona o me manda error , aunque sigo con la duda de como ejecutarlo con un sql dinamico ? tendras un ejemplo por favor

gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 18/12/2008 18:40:42
No entiendo el tipo de ejemplo que me pides, ¿me lo podrías aclarar un poco más?.
Te adjunto este código, que ejecuta mediante EXECUTE IMMEDIATE. Fíjate que se comporta exactamente como un SELECT... INTO de código estático.
En los comentarios de algunas líneas pongo ejemplos de sentencias que producirían diversas excepciones comunes.

declare
w_sql VARCHAR2(1000);
w_objId all_objects.object_id%TYPE;
begin
w_sql := 'SELECT object_id FROM all_objects where object_name=''UTL_FILE'' and object_type=''PACKAGE''';
-- Esta línea produciría TOO_MANY_ROWS ya que devuelve tres, objetos, UTL_FILE (Package),UTL_FILE (Package Body) y UTL_FILE (sinónimo)
--w_sql := 'SELECT object_id FROM all_objects where object_name=''UTL_FILE''';
-- La línea siguiente produciría NO_DATA_FOUND, ya que no hay ningún paquete llamado UT_FILE (a menos que lo hayas creado)
--w_sql := 'SELECT object_id FROM all_objects where object_name=''UT_FILE'' and object_type=''PACKAGE''';
BEGIN
execute immediate w_sql INTO w_objId;
dbms_output.put_line ('El id de objeto de la cabecera de UTL_FILE es: '|| w_objId);
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('No hay datos');
WHEN TOO_MANY_ROWS THEN
dbms_output.put_line ('Más de una fila');
END;
end;
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Alfredo (17 intervenciones) el 18/12/2008 19:45:32
Hola carlos disculpa el abuso mira este execute que hago a travez de una funcion

BEGIN

v_sql :='SELECT 1 INTO v_existe FROM DUAL WHERE EXISTS (SELECT OBJECT_NAME FROM USER_OBJECTS WHERE OBJECT_NAME ='
||CHR(39)||'WEB_AGREGADOC'||TRIM(v_sTipodocumentoid)||CHR(39) ||');
IF v_existe = 1 THEN cnumber := BNXAFILIACION.F_DROP_WEB_AGREGADOC(v_sDoctype);END IF;';

DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql;

EXCEPTION
WHEN OTHERS THEN

IF TO_CHAR(SQLCODE) = '-2260'
THEN
NULL;
ELSE
raise_application_error(-20001,'Error al borrar WEB_AGREGADOC- '||SQLCODE||' -ERROR- '||SQLERRM);
END IF;
END;
este bloque esta dentro de un store procedure y me manda el siguiente error , pero si lo ejecuto por fuera es decir como un bloque , lo realiza perfectamente . no se si omito algo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 19/12/2008 11:02:18
Hola, Alfredo.
No te preocupes, no es ningún abuso.
El problema que estás teniendo es que al EXECUTE IMMEDIATE le estás pasando un bloque PL/SQL inválido, intenta ejecutar el contenido de v_sql como
una sentencia SQL, no como un bloque PL/SQL.
Todo bloque PL/SQL, aunque sea dinámico, tiene que estar incluído dentro de las palabras clave BEGIN y END. Al no haberlas incluído, es el motor SQL el que intenta procesar la sentencia, y al encontrarse el primer ";" después de la SELECT, indica que ha encontrado un caracter no válido, porque al ejecutar una sentencia SQL con EXECUTE IMMEDIATE no se permite poner ";" al final, ya que ese carácter es un separador de sentencia.

Por tanto, lo que te aconsejo es lo siguiente:

1) Escribe un bloque PL/SQL estático válido que haga lo mismo que quieres hacer en el bloque dinámico. Por ejemplo:
DECLARE
c NUMBER;
BEGIN
c:= 5;
dbms_output.put_line (c);
END;
2) Ejecútalo, y comprueba que el resultado es el correcto. En tu caso, como es hacer un DROP de un objeto, quizá quieras sustituir esa operación por otra para hacer pruebas (un dbms_output, por ejemplo).
3) Pasa el bloque estático a dinámico. En mi ejemplo:
DECLARE
v_sql VARCHAR2(1000);
v_number NUMBER;
BEGIN
v_number := 3;
v_sql := ' DECLARE
c NUMBER;
BEGIN
c:= '||v_number ||';
dbms_output.put_line (c);
END;';
execute immediate (v_sql);
END;

4) Una vez que te funcione, y para aumentar el rendimiento, te aconsejo que en los manuales de Oracle mires el tema de las "Bind Variables" para pasar valores de enlace al SQL dinámico. Pero recuerda, sólo cuando te funcione y te sientas cómodo con el SQL dinámico.

Un saludo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 18/12/2008 18:41:52
Y otro que itera utilizando SQL dinámico. No tiene mucho sentido usar SQL dinámico en este caso, es un ejemplo sobre la marcha.

declare
w_sql VARCHAR2(1000);
w_objId all_objects.object_id%TYPE;
w_objName all_objects.object_name%TYPE;
c_data SYS_REFCURSOR;
begin
-- Lista de todos los paquetes de SYS. No sería necesario hacerlo con SQL dinámico, pero es un ejemplo.
w_sql := 'SELECT object_id, object_name FROM all_objects where object_type=''PACKAGE'' AND owner=''SYS''' ||
' And object_name like ''UTL%''';
-- Abrimos
Open c_data FOR w_sql;
-- Iteramos sobre todos los registros.
LOOP
FETCH c_data INTO w_objId, w_objName;
EXIT WHEN c_data%NOTFOUND;
dbms_output.put_line ('Id de paquete: ' || w_objId ||' -- Nombre de objeto: '|| w_objName);
END LOOP;
close c_data;
end;
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Alfredo (17 intervenciones) el 18/12/2008 19:12:50
el sql dinamico que quiero ejecutar es :

despues de que armo el query , lo pinto con el DBMS_OUTPUT.PUT_LINE(v_sql);
, y enseguida lo quiero ejecutar para que me devuelva el recordset con EXECUTE IMMEDIATE (v_sql);

pero me marca un error
ERROR en línea 1:
ORA-20001: Error execute - -911 -ERROR- ORA-00911: carácter no válido
ORA-06512: en "BNXAFILIACION.WEB_AC_OBTIENECAMPOS2", línea 87
ORA-06512: en línea 1

Carlos espero me haya explicado mejor , gracias por tu ayuda


CREATE OR REPLACE procedure BNXAFILIACION.web_Ac_Obtienecampos2
(
v_iDocid IN NUMBER DEFAULT NULL
-- cv_1 OUT SYS_REFCURSOR
)
AS

v_tabla VARCHAR2(50);
v_sql VARCHAR2(5000);
v_resultado VARCHAR2(5000);
v_i NUMBER(3,0);
v_max NUMBER(3,0);
v_campos NVARCHAR2(250);
v_campos2 NVARCHAR2(250);

BEGIN

BEGIN
SELECT tabla
INTO v_tabla
FROM TiposDocumento a,DIGITALIZAMAIN b
WHERE b.doctype = a.TipoDocumentoID
AND b.docid = v_iDocid;

EXCEPTION
WHEN OTHERS THEN v_tabla := NULL;
END;

IF v_tabla IS NULL OR v_tabla = '' THEN

DBMS_OUTPUT.PUT_LINE('Error, no existe el docid'||v_iDocid);
-- OPEN cv_1 FOR
-- SELECT v_iDocid ,'Error, no existe el docid'
-- FROM DUAL ;

ELSE
BEGIN

SELECT MAX(CampoID) + 1
INTO v_max
FROM CatCamposDocumento
WHERE Tabla = v_tabla;

v_sql := '';
v_i := 1;

WHILE v_i < v_max
LOOP
BEGIN
SELECT NVL(v_sql, '') || 'select ' ||to_char(v_iDocid) ||' as Docid,Nombrecampo as Campo,
nvl((select to_char(' || NombreCampo || ' )from ' || Tabla || ' where Docid = '|| to_char(v_iDocid) ||'),'|| CHR(39)|| ' '
|| CHR(39) || ') as ' || 'Valor ,to_char(NVL(PermisoID, 0) ) as PermisoID, TipoDato, LongitudMax, LongitudMin,
Obligatorio,Mostrar, Mascara, Regla,accion,TipoDatoConsulta, condicion1,condicion2,condicion3,
tipoDatoCliente from CatCamposDocumento where CampoID=' || TO_CHAR(v_i) || ' and Tabla= ' || CHR(39) || v_tabla || CHR(39) || '
union all '
INTO v_sql
FROM CatCamposDocumento
WHERE Tabla = v_tabla
AND CampoID = v_i;
--and Obligatorio=1

v_i := v_i + 1;


END;
END LOOP;

v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 11)||';';

BEGIN

DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE (v_sql);


EXCEPTION
WHEN OTHERS THEN

IF TO_CHAR(SQLCODE) = '-2260'
THEN
NULL;
ELSE
RAISE;
END IF;
END;
END;
END IF;
END;
/
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por alfredo (17 intervenciones) el 18/12/2008 19:54:14
en este caso solo quiero borrar un procedimiento , checando antes que no existe , pero el drop no me lo permite en un store procedure , asi que lo puse en una funcion , pero me devuelve el error de caracter no valido

ERROR en línea 1:
ORA-20001: Error al borrar WEB_AGREGADOC- -911 -ERROR- ORA-00911: carácter no
válido
ORA-06512: en "BNXAFILIACION.WEB_DELTIPODOCUMENTO", línea 38
ORA-06512: en línea 1

que podra ser o que estoy haciendo mal
o para borrar procedimientos de manera dinamica existe otra forma ¡?

gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 19/12/2008 10:42:31
Hola, Alfredo.

Es cierto que en PL/SQL no te permite sentencias DDL como el DROP, pero sin embargo en SQL dinámico te lo permite siempre, independientemente de que sea en un procedimiento o en una función.

Para borrarlo puedes utilizar EXECUTE IMMEDIATE. Te adjunto un script de ejemplo:

create procedure p_test IS
BEGIN
null;
END;
/

SELECT OBJECT_NAME FROM USER_OBJECTS WHERE object_name = 'P_TEST' AND OBJECT_TYPE='PROCEDURE';

BEGIN
EXECUTE IMMEDIATE ('DROP PROCEDURE P_TEST');
END;
/

SELECT OBJECT_NAME FROM USER_OBJECTS WHERE object_name = 'P_TEST' AND OBJECT_TYPE='PROCEDURE';
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por alfredo (17 intervenciones) el 19/12/2008 17:43:50
Carlos gracias , voy a corregir los bloques , y te aviso cuando me funcione , muchas gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Alfredo (17 intervenciones) el 22/12/2008 17:49:58
Carlos hice lo de el bloque , le puse begin end, pero ahora me manda un error , diciendome que esperaba un INTO , jeje creo que de plano no me deja , este es el script que estoy generando

CREATE OR REPLACE procedure BNXAFILIACION.web_Ac_Obtienecampos2
(
v_iDocid IN NUMBER DEFAULT NULL
-- cv_1 OUT SYS_REFCURSOR
)
AS

v_tabla VARCHAR2(50);
e_sql VARCHAR2(2000);
v_sql VARCHAR2(2000);
v_i NUMBER(3,0);
v_max NUMBER(3,0);
v_campos NVARCHAR2(250);
v_campos2 NVARCHAR2(250);
c_data SYS_REFCURSOR;

BEGIN

BEGIN
SELECT tabla
INTO v_tabla
FROM TiposDocumento a,DIGITALIZAMAIN b
WHERE b.doctype = a.TipoDocumentoID
AND b.docid = v_iDocid;

EXCEPTION
WHEN OTHERS THEN v_tabla := NULL;
END;

IF v_tabla IS NULL OR v_tabla = '' THEN

BEGIN
DBMS_OUTPUT.PUT_LINE('Error, no existe el docid'||v_iDocid);
END;

ELSE
BEGIN

SELECT MAX(CampoID) + 1
INTO v_max
FROM CatCamposDocumento
WHERE Tabla = v_tabla;

v_sql := '';
v_i := 1;

WHILE v_i < v_max
LOOP
BEGIN

SELECT NVL(v_sql, '') || 'SELECT ' ||TO_CHAR(v_iDocid) ||' AS Docid,Nombrecampo AS Campo,
NVL((SELECT TO_CHAR(' || NombreCampo || ' )FROM ' || Tabla || ' WHERE Docid = '|| TO_CHAR(v_iDocid) ||'),'|| CHR(39)|| ' '
|| CHR(39) || ') AS ' || 'Valor ,TO_CHAR(NVL(PermisoID, 0) ) AS PermisoID, TipoDato, LongitudMax, LongitudMin,
Obligatorio,Mostrar, Mascara, Regla,accion,TipoDatoConsulta, condicion1,condicion2,condicion3,
tipoDatoCliente from CatCamposDocumento WHERE CampoID=' ||
TO_CHAR(v_i) || ' AND Tabla= ' || CHR(39) || v_tabla || CHR(39) ||' UNION ALL '
INTO v_sql
FROM CatCamposDocumento
WHERE Tabla = v_tabla
AND CampoID = v_i;
--and Obligatorio=1

v_i := v_i + 1;


END;
END LOOP;

BEGIN
DBMS_OUTPUT.put_line('entra a desplegar');
v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 11)||';';
e_sql := 'BEGIN ' ||v_sql ||' END;';
DBMS_OUTPUT.put_line(e_sql);
EXECUTE IMMEDIATE(e_sql);
e_sql := 'CREATE VIEW view_web_ac AS' ||v_sql||';';
END;
END;
END IF;

END;
/
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 24/12/2008 10:07:41
Hola, Alfredo.
Lo que te ocurre es normal.
Estás enviando al EXECUTE IMMEDIATE el siguiente código:

BEGIN
SELECT xxxx as DocId ...
UNION ALL
SELECT xxxx as Docid ... ;
END;

En un bloque PL/SQL toda sentencia SELECT que aparezca debe tener una claúsula INTO.
Pero en este caso veo que en realidad no necesitas un bloque PL/SQL.

Lo que quieres es recuperar las N filas de la sentencia, por tanto puedes sustituir las líneas

e_sql := 'BEGIN ' ||v_sql ||' END;';
DBMS_OUTPUT.put_line(e_sql);
EXECUTE IMMEDIATE(e_sql);

Por una línea equivalente a la siguiente.

OPEN CV_1 FOR v_sql;

donde CV_1 ha de ser un REF CURSOR. Veo que tenías un parámetro de este tipo (que ya no tienes), así que con esa sentencia el programa abriría un cursor sobre la sentencia SELECT.
En resumen, cuando una sentencia SELECT dinámica como la que tú tienes devuelve más de una fila, has de abrir un cursor sobre ella para recuperar los datos, no puedes utilizar el EXECUTE IMMEDIATE (bueno, poder puedes pero te dará errores).

Por otra parte, estoy mirando la sentencia SELECT que construyes, y veo que tiene una estructura similar a esta:

SELECT xxxx as DocId ... FROM CatCamposDocumento
WHERE Tabla = <tabla>
AND CampoID = <primer Id>
UNION ALL
SELECT xxxx as Docid ... FROM CatCamposDocumento
WHERE Tabla = <tabla>
AND CampoID = <segundo Id>
...

Es decir, que recuperas, de CatCamposDocumento los campos necesarios, siempre que el campo Tabla tenga un valor definido, que no cambia nunca entre las SELECT que participan en la UNION, y el CampoId esté entre el primero y el último, inclusive.

Pero esto es lo mismo que hacer

SELECT xxxx as DocId ... FROM CatCamposDocumento
WHERE Tabla = <tabla>

Esta sentencia te recupera igualmente los datos, entre el primer y el último Id de campo, ya que estás recuperando todos no necesitas especificar cuales recuperas, con lo cual no necesitarías controlar el Id de campo, ni de hecho tener un bucle, y además la sentencia te quedaría mucho más compacta para construirla con SQL dinámico.

Puede que me equivoque, no conozco las especificaciones de la aplicación.

Un saludo,
Carlos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por ALFREDO (17 intervenciones) el 26/12/2008 18:51:17
QUE TAL CARLOS , YA PROBE EL CURSOR , PERO NO MUESTRA NADA , ME MANDA EL SIGUIENTE ERROR , CREO QUE TODO ESTA BIEN
*
ERROR en línea 1:
ORA-00911: carácter no válido
ORA-06512: en "BNXAFILIACION.WEB_AC_OBTIENECAMPOS2", línea 76
ORA-06512: en línea 1

CREATE OR REPLACE procedure BNXAFILIACION.web_Ac_Obtienecampos2
(
v_iDocid IN NUMBER DEFAULT NULL

)
AS

/*
Autor:Adriana Robles Yong
Fecha:8 de Febrero de 2007
DEscripcion:Procedimiento para obtencion de campos de actualización
*/
v_tabla VARCHAR2(50);
e_sql VARCHAR2(2000);
v_sql VARCHAR2(2000);
v_i NUMBER(3,0);
v_max NUMBER(3,0);
v_campos NVARCHAR2(250);
v_campos2 NVARCHAR2(250);
v_cursor SYS_REFCURSOR;

BEGIN

BEGIN
SELECT tabla
INTO v_tabla
FROM TiposDocumento a,DIGITALIZAMAIN b
WHERE b.doctype = a.TipoDocumentoID
AND b.docid = v_iDocid;

EXCEPTION
WHEN OTHERS THEN v_tabla := NULL;
END;

IF v_tabla IS NULL OR v_tabla = '' THEN

BEGIN
DBMS_OUTPUT.PUT_LINE('Error, no existe el docid'||v_iDocid);
END;

ELSE
BEGIN

SELECT MAX(CampoID) + 1
INTO v_max
FROM CatCamposDocumento
WHERE Tabla = v_tabla;

v_sql := '';
v_i := 1;

WHILE v_i < v_max

LOOP
SELECT NVL(v_sql, '') || 'SELECT ' ||TO_CHAR(v_iDocid) ||' AS Docid,Nombrecampo AS Campo,
NVL((SELECT TO_CHAR(' || NombreCampo || ' )FROM BNXAFILIACION.' || Tabla ||
' WHERE Docid = '|| TO_CHAR(v_iDocid) ||'),'|| CHR(39)|| ' '|| CHR(39) || ') AS ' ||
'Valor ,TO_CHAR(NVL(PermisoID, 0) ) AS PermisoID, TipoDato, LongitudMax, LongitudMin,
Obligatorio,Mostrar, Mascara, Regla,accion,TipoDatoConsulta, condicion1,condicion2,condicion3,
tipoDatoCliente FROM bnxafiliacion.CatCamposDocumento WHERE CampoID=' ||
TO_CHAR(v_i) || ' AND Tabla= ' || CHR(39) || v_tabla || CHR(39) ||' UNION ALL '
INTO v_sql
FROM BNXAFILIACION.CatCamposDocumento
WHERE Tabla = v_tabla
AND CampoID = v_i;
--and Obligatorio=1

v_i := v_i + 1;


END LOOP;

v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 11)||';';
DBMS_OUTPUT.put_line(v_sql);
OPEN v_cursor FOR v_sql;


END;

END IF;

END;
/
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Ejecutar Funcion

Publicado por Carlos (17 intervenciones) el 29/12/2008 10:53:54
Hola, Alfredo.
En la línea

v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 11)||';';

le estás concatenando un carácter ';' a la sentencia. No se lo concatenes, y luego al menos no debiera fallar por eso (quien sabe si por otra cosa ;) ).
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar