Las bases de datos del Firebird sirven para guardar datos en ellas, para procesar dichos datos y para consultarlos cuando se los necesita.
- En las tablas se guardan los datos
- En los stored procedures y en los triggers se procesan los datos
- Con las vistas se consultan los datos
Los stored procedures (procedimientos almacenados) son los equivalentes a las rutinas, procedimientos, o funciones disponibles en casi todos los lenguajes de programación (Visual FoxPro, Visual Basic, C, Delphi, Java, etc.), allí se utilizan los datos que se encuentran en las tablas, se realizan operaciones aritméticas o lógicas sobre esos datos y se devuelve el resultado de ese procesamiento.
Los stored procedures pueden recibir cero, uno, o varios parámetros de entrada y devolver cero, uno, o varios parámetros de salida.
En Firebird hay dos clases de stored procedures:
- Ejecutables
- Seleccionables
Los stored procedures ejecutables son llamados de manera similar a como se llaman las rutinas, procedimientos o funciones en los lenguajes de programación, por ejemplo:
EXECUTE PROCEDURE MiStoredProcedureEjecutable(123, ‘Firebird me gusta’)
Los stored procedures seleccionables en cambio son utilizados como si fueran tablas en un SELECT, por ejemplo:
SELECT * FROM MiStoredProcedureSeleccionable(123, ‘Firebird me gusta’)
La forma de escribirlos es casi la misma. Las únicas diferencias son:
- Los stored procedures ejecutables pueden devolver cero filas o una fila, jamás pueden devolver más de una fila
- Los stored procedures seleccionables pueden devolver cero filas, una fila, o muchas filas
- Cuando finaliza un stored procedure ejecutable devuelve todos los parámetros de salida. Todos esos parámetros de salida son devueltos en una fila y solamente en una fila, jamás en más de una fila
- Cada vez que un stored procedure seleccionable encuentra el comando SUSPEND le devuelve al SELECT que lo llamó todos los parámetros de salida, con los valores que tienen asignados en ese momento. O sea que devuelve una fila cada vez que encuentra el comando SUSPEND.
Veamos un ejemplo de un stored procedure ejecutable:
CREATE PROCEDURE EXISTE_NUMERO_DOCUMENTO( tcNroDoc TYPE OF COLUMN VENTASCAB.VTC_NRODOC) RETURNS( ftcDocumentoExiste TYPE OF D_BOOLEAN) AS DECLARE VARIABLE lcNroDoc TYPE OF COLUMN VENTASCAB.VTC_NRODOC; BEGIN SELECT COALESCE(V.VTC_NRODOC, '') -- Si VTC_NRODOC es nulo, devuelve una cadena vacía FROM VENTASCAB V WHERE V.VTC_NRODOC = :tcNroDoc INTO :lcNroDoc; ftcDocumentoExiste = 'F'; IF (tcNroDoc = lcNroDoc) THEN ftcDocumentoExiste = 'V'; END;
- Este stored procedure se llama EXISTE_NUMERO_DOCUMENTO
- Recibe un parámetro de entrada llamado tcNroDoc cuyo tipo de datos es el mismo que tiene la columna VTC_NRODOC de la tabla VENTASCAB
- Devuelve un parámetro de salida llamado ftcDocumentoExiste, el cual es de tipo D_BOOLEAN y por lo tanto puede valer «V» o «F»
- Usa una variable que es local al stored procedure y cuyo nombre es lcNroDoc y su tipo también es igual al de la columna VTC_NRODOC
- Busca en la tabla VENTASCAB un documento cuyo número sea igual al del parámetro de entrada (tcNroDoc) y guarda el resultado en la variable lcNroDoc
- Supone que el documento que se está buscando no existe
- Compara el parámetro de entrada tcNroDoc con el resultado de la búsqueda que se guardó en la variable lcNroDoc. Si son iguales eso significa que se encontró el número de documento buscado
- Al terminar el stored procedure se devuelve el valor de la variable ftcDocumentoExiste (que puede ser o «V» o «F») ya que ftcDocumentoExiste es el parámetro de salida
Veamos ahora un ejemplo de un stored procedure seleccionable:
CREATE PROCEDURE PRODUCTOS_CLASIFICADOS RETURNS(tnResultado SMALLINT) AS DECLARE VARIABLE lnPreVta TYPE OF COLUMN PRODUCTOS.PRD_PREVTA; BEGIN FOR SELECT PRD_PREVTA FROM PRODUCTOS INTO :lnPreVta DO BEGIN IF (lnPreVta < 1000) THEN tnResultado = 1; IF (lnPreVta >= 1000 AND lnPreVta <= 50000) THEN tnResultado = 2; IF (lnPreVta > 50000) THEN tnResultado = 3; SUSPEND; END END
Este stored procedure lo que hace es clasificar a los productos según sus precios de venta: si el precio de venta es menor que 1.000, devuelve 1. Si el precio de venta está entre 1.000 y 50.000 devuelve 2. Si el precio de venta es mayor que 50.000 devuelve 3.
Cada vez que se llega al SUSPEND el parámetro de salida tnResultado se devuelve al SELECT para que éste lo muestre. Después que se le entregó al SELECT el parámetro de salida tnResultado se procesa la siguiente fila, y así hasta procesarlas a todas las filas. Al SELECT se le devolverá una fila cada vez que se encuentre un SUSPEND. Entonces, si la tabla PRODUCTOS tiene 1.800 filas, este stored procedure seleccionable devolverá 1.800 filas.
SELECT * FROM PRODUCTOS_CLASIFICADOS
Aunque PRODUCTOS_CLASIFICADOS es un stored procedure se lo utiliza como si fuera una tabla. ¿Por qué? porque es un stored procedure seleccionable ¿Y cómo sabemos que es un stored procedure seleccionable? Porque tiene el comando SUSPEND dentro suyo.
Resumiendo:
- Los stored procedures se utilizan para procesar datos
- Hay dos clases de stored procedures:
- Ejecutables
- Seleccionables
- Los stored procedures ejecutables son llamados con EXECUTE PROCEDURE y pueden devolver cero filas o una fila
- Los stored procedures seleccionables son llamados con SELECT y pueden devolver cero filas, una fila o muchas filas
- La forma de escribirlos es casi la misma, la diferencia es que en los stored procedures ejecutables cuando finalizan devuelven los parámetros de salida, en cambio los stored procedures seleccionables devuelven los parámetros de salida cada vez que encuentran el comando SUSPEND
- Cuando finaliza un stored procedure ejecutable devuelve sus parámetros de salida, con los valores que tienen en ese momento
- Cada vez que un stored procedure seleccionable encuentra al comando SUSPEND devuelve sus parámetros de salida con los valores que tienen en ese momento
Artículos relacionados:
Entendiendo las excepciones | Firebird SQL
May 12, 2013 @ 12:03:06
Importar datos desde otra Base de Datos | Firebird SQL
May 16, 2013 @ 12:15:06
El índice del blog Firebird21 | Firebird SQL
Jun 17, 2013 @ 04:46:08
¿Es conveniente usar stored procedures? | Firebird SQL
Jun 20, 2013 @ 21:23:27
Similitudes y diferencias entre stored procedures y triggers | Firebird SQL
Jun 28, 2013 @ 22:30:43
Flako
Dic 23, 2013 @ 20:25:04
hace un momento hice una pregunta acerca de un procedure que no comprendia, he leido este tema pero sigo sin comprender, el procedure que estoy haciendo solo hace una consulta select identificador from tabla where tipo=’c’ por asi decirlo, el problema es que no me muestra todas las filas, al contrario me manda el error de las multiples filas en una consulta simple
Multiple rows in singleton select, ya estoy comenzando a desesperarme…
:S
mira haber si se le entiende o haber si me puedes ayudar porfavor
create or alter procedure BUSCA_ID (
DESDE date,
HASTA date)
returns (identificador integer)
as
begin
select docto_cm_id
from doctos_cm
inner join proveedores on
(doctos_cm.proveedor_id = proveedores.proveedor_id)
where (doctos_cm.tipo_docto = ‘r’)
and (doctos_cm.estatus ‘C’)
and (doctos_cm.fecha > :DESDE)
and (doctos_cm.fecha < :HASTA)
and (proveedores.proveedor_id not like 123456)
into identificador;
suspend;
end
wrov
Dic 23, 2013 @ 20:33:54
Después de doctos_cm.estatus te faltó un operador de comparación antes de escribir ‘C’
El NOT LIKE se usa para comparar strings, no números. Para comparar números deberías usar menor que, mayor que
El INTO Identificador debe llevar dos puntos antes de Identificador, debería ser: INTO :Identificador
Si utilizas el comando SUSPEND entonces tu stored procedure es seleccionable, como lo dice el artículo, y debes llamarlo con un SELECT.
Saludos.
Walter.
Flako
Dic 24, 2013 @ 15:15:28
Disculpa amigo ya hice las correcciones que me marcaste, es solo que no hago que funcione jaja me marca el error de las multiples filas nuevamente pero ahora quiero que esos valores que toma la consulta los pase a otro procedure para que me genere una operación matemática agregar un:
execute procedure operacion (resultado de la consulta), tipo_docto pero mi intencion es que tome un valor a la vez y me regrese el resultado
wrov
Dic 24, 2013 @ 15:34:20
Flako, como te dije antes, si Firebird te muestra el error: «multiple rows in singleton select» significa que tu subconsulta está devolviendo varias filas y debería devolver solamente una. Revisa tu subconsulta.
Si quieres un ciclo tienes dos formas de hacerlo: a) con un FOR SELECT, o b) con un WHILE()
Saludos.
Walter.
Nacho
Ene 20, 2014 @ 09:09:05
Muchas gracias por la explicación, me ha sido de mucha ayuda para un problema que me surgió en el trabajo.
wrov
Ene 20, 2014 @ 12:04:28
De nada, si tienes cualquier duda sobre Firebird, sólo pregunta.
Saludos.
Walter.
Carlos Rodriguez
Ene 23, 2014 @ 13:03:40
Estoy arrancando con Firbird, trabajo con vb6 y access, por lo que uso la funcion select * from tabla where cvdate(’01/12/13′) = tabla.fecha
Me podras decir que udf debo crear para que me convierta ese cvdate? desde ya muchas gracias.
wrov
Ene 23, 2014 @ 13:11:47
En Firebird no necesitas usar una función, pero los separadores tienen significado:
MM/DD/AAAA
DD-MM-AAAA
AAAA.MM.DD
Para evitar confusiones puede ser preferible usar la abreviatura (en inglés) de los nombres de los meses:
23/JAN/2014
JAN/23/2014
Saludos.
Walter.
David Jiménez
May 05, 2014 @ 08:33:08
¿Es posible tener FOR anidados?
Tengo una consulta con FOR anidados y el primero lo hace bien, pero cuando llega al segundo vuelve al primero y no le ejecuta
Gracias por tu foro, es de gran ayuda
wrov
May 05, 2014 @ 09:07:19
Sí, no hay problemas, puedes tenerlos.
Deberías revisar el código que escribiste, hay algo que no está bien.
Le agregué dos artículos al blog relacionados con los FOR SELECT.
Saludos.
Walter.
David Jiménez
May 05, 2014 @ 12:19:53
Muchas gracias por tus respuestas
He revisado el código y he encontrado que un select no daba resultados, por eso lo saltaba, pero sigue sin funcionar bien.
Ademas SUSPEND no lo coloqué en el lugar adecuado, porque no entiendo bien para que sirve.
Lo he colocado al final de todos los bucles, pero sólo obtengo una fila.
¿Tengo que poner más de un SUSPEND, o con uno debía de ser suficiente?
wrov
May 05, 2014 @ 17:24:53
David, el SUSPEND sirve para devolver los parámetros de salida. Es decir, los que se encuentran después del RETURNS.
Puedes tener un SUSPEND o muchos SUSPEND, los que necesites. El valor que al llegar al SUSPEND tengan los parámetros de salida serán los que se devolverán.
Para entender mejor, los SUSPEND se utilizan en los stored procedures seleccionables. Puedes leer el artículo:
para captar mejor la idea y como se usan.
Saludos.
Walter.
David Jiménez
May 06, 2014 @ 05:25:29
Gracias por tu respuesta
Leyendo nuevamente tu artículo he encontrado por fin el error.
Tenía varios Procedimientos Almacenados enlazados, unos de tipo ejecutable y otros de tipo Seleccionable, y coloqué algún SUSPEND pero no estaba bien.
Como los Ejecutables devolvian parámetros puse el SUSPEND, que ahora sé que sólo se debe poner cuando los Seleccionables devuelven parámetros nunca con los Ejecutables
Un saludo y enhorabuena por tu magnífico blog
wrov
May 06, 2014 @ 10:39:32
Que bueno que lo hayas solucionado y de paso que hayas aprendido algo nuevo.
Saludos.
Walter.
Felipe
Jun 02, 2014 @ 21:54:02
create procedure busMuni(out nombre varchar(50))
begin
select bq1.name from (Select nomMpio name from depto, mpio where id=iddepto and nombreDepto=nombre) as bq1
suspend;
end+
este procedure me devuelve varios datos (nombres de municipiios) mm y nose como retornarlos para que pueda llamarlos y visualizarlos desde java
Gracias (Y)
wrov
Jun 02, 2014 @ 21:59:51
Si quieres devolver varias filas de una tabla, no debes usar SELECT sino que debes usar FOR SELECT, y poner el comando SUSPEND dentro de ese FOR SELECT.
Saludos.
Walter.
Felipe
Jun 04, 2014 @ 01:01:57
Y podre visualizarlos en una caja de texto desde java? (Y) «trabajando en ello»
wrov
Jun 04, 2014 @ 01:20:10
Por supuesto que sí ¿por qué no podrías?
Saludos.
Walter.
Felipe
Jun 04, 2014 @ 02:18:41
Walter necesito su ayuda. en verdad me intereso por aprender y solucionar mis inquietudes.
wrov
Jun 04, 2014 @ 10:17:50
Explícame claramente lo que necesitas y trataré de ayudarte, envía tu pedido a mi e-mail: wrov@hotmail.com
Por supuesto que no escribiré todo el stored procedure por tí, sino que te iré guiando hasta que obtengas lo que deseas.
Saludos.
Walter.
felipe
Jun 04, 2014 @ 13:18:09
bn Walter (Y) envio la info.
felipe
Jun 04, 2014 @ 16:30:18
Walter ya envie la inf a su correo. Todo bn
juan carlos ramirez
Jul 04, 2014 @ 19:30:32
Buenas tardes walter,, los procedimientos almacenados son muy utiles, pero se puede evitar que alguien ajeno borre un Stored Procedures ? , se podrian blindar ? gracias por tu ayuda
Jaume
Jul 17, 2014 @ 04:15:15
He tenido problemas últimamente con un sp y he descubierto una carácteristica que no sabía y lo expongo aquí por por si ha alguien le ha pasado como a mi.
Si en un sp tengo que asignar un valor a una variable con un select, ejemplo:
Select codcli from clientes where coot = ‘1234’ into codcli;
si antes de este select, por lo que sea, hemos inicializado la variable con un valor cualquiera, ejemplo codcli = ‘nada’ y la consulta no saca ningún valor, yo pensaba que :codcli valdría null, pero NO, sigue teniendo el valor anterior que le habíamos asignado, es decir, en este ejemplo sería ‘nada’.
wrov
Sep 07, 2014 @ 14:12:26
Jaume, eso es porque un SELECT puede devolver cero filas, eso ocurre cuando la tabla no tiene filas o cuando ninguna fila cumple con la condición. En ese caso el valor que tenían las variables asignadas por el SELECT (las que se encuentran después de la cláusula INTO) no puede cambiar ya que ninguna fila fue retornada. La asignación a esas variables se hace solamente después de obtener una fila, como es lógico.
En consecuencia, si ninguna fila es retornada todas esas variables mantienen el valor que tenían anteriormente, porque ninguna asignación fue hecha a ellas. En tu caso, CODCLI seguirá valiendo ‘nada’.
Para que CODCLI valiera NULL, el Firebird tendría que asignarle NULL antes de ejecutar al SELECT pero ¿para qué haría eso? sería una causa de conflicto porque una columna de un SELECT puede legítimamente valer NULL y en ese caso ¿cómo se diferenciaría entre un NULL previamente asignado y un NULL como valor legítimo de una columna? No habría forma de diferenciar a un NULL del otro, por lo tanto el Firebird hace lo más lógico, coherente, y racional: asignarle valores a las variables solamente después de obtener una fila del SELECT, nunca antes.
Así que, el Firebird hace lo correcto.
Saludos.
Walter.
Jaume
Sep 07, 2014 @ 14:20:33
Gracias Walter por la aclaración, hasta que caí en ello, no se me había ocurrido.
Epic angeles (Angie2014)
Sep 18, 2014 @ 14:37:08
Hola, apenas empiezo con los stored procedures, estoy haciendo uno seleccionable, pues ahi todo bien con mi primer for select, pero despues de obtener estos datos necesito hacer un select que me regrese una sola fila de un registro para obtener el ultimo tipo de cambio, y convertir los montos de dolares a pesos, dichos montos me los traigo en el for select, bueno lo que me pasa es que pongo el select y me marca error, me podrian decir si tengo algo mal en la sintaxis? ya que me marca error Invalid token:
Dynamic SQL Error.
SQL error code = -104.
Token unknown – line 48, char 17.
select.
Este es el cuerpo de mi stored procedure,quitando ese ultimo select todo me sale bien. la variable reg_monid es integer.
begin
FOR SELECT A.FOLIO, A.clave_prov,A.proveedor_id,a.moneda_id,A.fecha, A.descripcion, b.nombre,c.simbolo,
d.posicion, d.articulo_id,d.clave_articulo,d.unidades_a_rec,D.unidades ,d.precio_unitario
FROM doctos_cm A
join proveedores b on a.proveedor_id = b.proveedor_id
join monedas c on a.moneda_id = C.moneda_id
join doctos_cm_det D on a.docto_cm_id = d.docto_cm_id and d.unidades > D.unidades_rec_dev
where A.ESTATUS = ‘P’
AND A.TIPO_DOCTO = ‘O’
AND (A.FECHA BETWEEN :V_FECHA_INI AND :V_FECHA_FIN)
order by a.folio
INTO: OC_FOLIO ,PROVEEDOR_CVE, PROVEEDOR_ID, MONEDAID ,FECHAOC,DESCRIPCION,PROVEEDOR_NOM, MONEDA,posicion,
id_prod, clave_articulo, unidadesp, unidadeso,preciou
select first 1 E.historia_camb_id
from historia_cambiaria E WHERE MONEDA_ID =:168
ORDER BY FECHA DESC
into: reg_monid;
DO
SUSPEND;
end
wrov
Sep 18, 2014 @ 22:03:13
Tu segundo SELECT está mal ubicado, debería estar después del DO y antes del SUSPEND.
Saludos.
Walter.
Henry Gallardo
Feb 13, 2015 @ 22:40:06
Hola Walter, después de tiempo que recurro a tu experiencia, y desde ya quedo muy agradecido por tu consejo.
Te cuento que estoy migrando un sistema en VFP 9 a firebir y uso tu clase, y el problema que tengo es que al pasar parámetros al SP, me doy con la sorpresa que solo puedo pasar 26 parametros y supero ese numero, no se que hacer espero que puedas ayudarme, te copio un pedazo del código para que de des cuenta.
SCAN
witem = witem + 1
WANULA = v_movimien.anula
WANO_MES = oApp.año + ‘-‘ + oApp.mes
WLIBRO = v_movimien.libro
WASIENTO = v_movimien.asiento
WITEM = strzero( VAL( witem ) , 4 )
WFECHA = v_movimien.fecha
WCTACTE = v_movimien.ctacte
WTIPDOC = v_movimien.tipdoc
WSERDOC = v_movimien.serdoc
WNUMDOC = v_movimien.numdoc
WFECDOC = v_movimien.fecdoc
WVCTO = v_movimien.vcto
WTIPREF = v_movimien.tipref
WSERREF = v_movimien.serref
WNUMREF = v_movimien.numref
WFECREF = v_movimien.fecref
WNUMDETRA = v_movimien.numdetra
WFECDETRA = v_movimien.fecdetra
WPOR_DET = v_movimien.por_det
WPOR_PER = v_movimien.por_per
WTRABAN = v_movimien.traban
WADUANA = v_movimien.aduana
WGLOSA = ALLTRIM( v_movimien.glosa )
WGIRADO = v_movimien.girado
WOPERACION = v_movimien.operacion
WVVENTA = v_movimien.vventa
WISC = v_movimien.isc
WIGV = v_movimien.igv
WNOGRAVADO = v_movimien.nogravado
WOTROS = v_movimien.otros
WTOTAL = v_movimien.total
WCUENTA = v_movimien.cuenta
WTC = v_movimien.tc
WMONEDA = v_movimien.moneda
WDEB_S = v_movimien.deb_s
WHAB_S = v_movimien.hab_s
WDEB_D = v_movimien.deb_d
WHAB_D = v_movimien.hab_d
WACCIONES = v_movimien.acciones
WF_CAJA = v_movimien.f_caja
WCODREP = v_movimien.codrep
WREPARO = v_movimien.reparo
WCONCILIADO = v_movimien.conciliado
WFECCAJA = v_movimien.feccaja
WENLACE = v_movimien.enlace
WENLACE_CC = v_movimien.enlace_cc
WPF = v_movimien.pf
WALMA = v_movimien.alma
WCODVEN = v_movimien.codven
WUSUARIO = v_movimien.usuario
WTERMINAL = terminal
WFEC_MOD = v_movimien.fec_mod
WHORA = v_movimien.hora
TEXT TO lcFila NOSHOW
EXECUTE PROCEDURE GRABAR_MOVIMIEN( ?WANULA, ?WANO_MES, ?WLIBRO, ?WASIENTO, ?WITEM, ?WFECHA, ?WCTACTE, ?WTIPDOC, ?WSERDOC,
?WNUMDOC, ?WFECDOC, ?WVCTO, ?WTIPREF, ?WSERREF, ?WNUMREF, ?WFECREF, ?WNUMDETRA, ?WFECDETRA,
?WPOR_DET, ?WPOR_PER, ?WTRABAN, ?WADUANA, ?WGLOSA, ?WGIRADO, ?WOPERACION, ?WVVENTA, ?WISC,
?WIGV, ?WNOGRAVADO, ?WOTROS, ?WTOTAL, ?WCUENTA, ?WTC, ?WMONEDA, ?WDEB_S, ?WHAB_S, ?WDEB_D,
?WHAB_D, ?WACCIONES, ?WF_CAJA, ?WCODREP, ?WREPARO, ?WCONCILIADO, ?WFECCAJA, ?WENLACE, ?WENLACE_CC,
?WPF, ?WALMA, ?WCODVEN, ?WUSUARIO, ?WTERMINAL, ?WFEC_MOD, ?WHORA )
ENDTEXT
Grabo_ok = oSQL2.Ejecutar( lcFila , ‘v_movimien’ )
ENDSCAN
Esteban
Feb 15, 2015 @ 22:30:01
Hola Henry.
Yo creo q tenes algún otro drama en tu SP, yo tengo uno q uso muy frecuentemente y tiene 61 parámetros y los grabo desde VFP sin ningún tipo de inconvenientes.
wrov
Feb 13, 2015 @ 23:38:23
Hola
No sabía que había un límite de 26 parámetros, es raro, me parece poco.
De todas maneras hay una solución muy sencilla para solucionar tu problema y es grabar en 2 partes
– Con el primer EXECUTE PROCEDURE grabas 25 columnas
– Con el segundo EXECUTE PROCEDURE grabas las columnas restantes
Para asegurarte que siempre se grabe en la misma fila deberías verificar que el Identificador sea el mismo para ambos casos.
Saludos.
Walter.
Henry Gallardo
Feb 13, 2015 @ 23:43:11
Muchas gracias Walter por tu consejo, me pregunto si puedo pasar un array como parámetro y si firebir lo soporta y como seria el SP.
Muchas gracias por molestarte
wrov
Feb 14, 2015 @ 01:03:09
De nada.
Los arrays son uno de los puntos flojos del Firebird, no te recomiendo usarlos todavía.
Pero lo que si puedes hacer es guardar tus datos en un archivo .TXT y luego importarlo.
Saludos.
Walter.
Jaume
Feb 14, 2015 @ 05:02:11
Yo tengo un caso parecido, aunque no con tantos parametros y lo que hago es juntar todos los parametros en una cadena separada por algún carácter especial, el que sea, entonces le paso un solo parámetro al sp y el sp por medio de una llamada a otro sp que lo que hace es separar la cadena por el carácter especial que le indicamos, simulando la función explode de php, nos va dando cada uno de los parámetros, tanto da que sean 1 como 100.
Si esto te sirve, te puedo pasar el sp que hace el explode.
Henry Gallardo
Feb 14, 2015 @ 11:31:39
Hola Jaume, me da alegría que personas como tu ayuden a la comunidad y desde ya estaría muy agradecido si me pasas los SP, mi correo es henry_gallardo_m@yahoo.es
chaooooo
Walter
Feb 14, 2015 @ 11:37:04
Lo que comenta Jaume es otra posibilidad, hay un artículo en este blog que te muestra la técnica:
Saludos.
Walter.
Henry Gallardo
Feb 14, 2015 @ 13:32:35
Muchas gracias Walter, lo voy a revisar
chaooooo
Henry Gallardo
Feb 17, 2015 @ 11:13:54
Hola Walter, hace unos días hice un comentario sobre la cantidad de parámetros en un SP y dije que solo aceptaba hasta 26, era por una función que tengo en vfp9 y me dio ese error el que yo asumí que era de firebird y como dice el amigo Esteban es cierto ya corregí mi función y puedo grabar mas de 60 campos, hago esta aclaración para no confundir a los amigos que leen este foro que tan dignamente documentas con tu experiencia, desde ya mil disculpas a ti y a todos los lectores
Ignacio
Abr 16, 2016 @ 08:07:01
Hola Walter, enhorabuena por esta magnífica web sobre Firebird.
Con esto de los Stored Procedures me ha quedado una duda, a ver si me la podrías resolver. Imaginemos que llamo a un stored procedures ejecutable desde un lenguaje de programación, digamos desde Pascal, y que quiero almacenar el resultado del stored procedure ejecutable dentro de una variable de mi programa en Pascal. Cómo podría hacerlo?
Muchas gracias.
wrov
Abr 16, 2016 @ 13:02:32
Hola Ignacio
Gracias por el comentario positivo.
Simplemente llamas al stored procedure ejecutable desde tu lenguaje de programación y los parámetros de salida ya estarán disponibles para ser usados. Serán tratados como variables locales allí.
Por ejemplo, si el parámetro de salida se llama ftnTotalVentasMes, desde tu lenguaje de programación podrás usarlo para mostrarlo en la pantalla, imprimirlo, aplicarlo en alguna fórmula, compararlo, etc.
Saludos.
Walter.
Jose David
Sep 13, 2016 @ 16:48:21
Hola tengo un problema al llamar un Stored Procedure desde una instancia PDO de php, NO me funciona el parametro CALL, asi que utilice el EXECUTE PROCEDURE, pero no me esta devolviendo ningun parametro de salida, e intento llamar al procedure desde SELECT * FROM y me sale este error: invalid request BLR at offset 106 (El numero cambia cuando llamo a otro procedure) Si alguien me podria ayudar.
wrov
Sep 14, 2016 @ 00:09:06
¿Y tu stored procedure tiene algún parámetro de salida?
Saludos.
Walter.
Jose David
Sep 14, 2016 @ 11:01:32
Hola, Si tiene parámetro de salida, pero ya solucione el problema estaba en que el Stored Procedure no tenia la linea al final de SUSPEND; al cual al llamarlo con el SELECT me trajo el ID que necesitaba. Muchas Gracias por tu blog me hizo de mucha ayuda
Jorge Traslaviña
Feb 08, 2017 @ 10:16:27
Hola Walter, disculpa no encontré donde más hacerte esta consulta… me surgió por un error involuntario al compilar un procedure…
CREATE PROCEDURE TAB_MERCANCI_S_1(
MERREF TYPE OF NUMSMA)
RETURNS(
MERMED TYPE OF VARC20,
MERALT TYPE OF NUMDEC,
MERLAR TYPE OF NUMDEC,
MERANC TYPE OF NUMDEC,
MERCAN TYPE OF NUMINT)
AS
BEGIN
FOR
SELECT MERMED,
MERALT,
MERLAR,
MERANC,
MERCAN
FROM TAB_MERCANCI
WHERE MERREF = :MERREF
INTO :MERMED,
:MERALT,
:MERLAR,
:MERCAN,
:MERCAN
DO
BEGIN
SUSPEND;
END
END
Es procedimiento compila a pesar que la variable de resultado :MERCAN está duplicada, no encuentro una explicación para que acepte tal caso.
Por curiosidad compilé
CREATE PROCEDURE TAB_MERCANCI_S_2(
MERREF TYPE OF NUMSMA)
RETURNS(
MERMED TYPE OF VARC20,
MERLAR TYPE OF NUMDEC,
MERANC TYPE OF NUMDEC,
MERALT TYPE OF NUMDEC,
MERCAN TYPE OF NUMINT)
AS
BEGIN
FOR
SELECT MERMED,
MERLAR,
MERANC,
MERALT,
MERCAN
FROM TAB_MERCANCI
WHERE MERREF = :MERREF
INTO :MERMED,
:MERANC,
:MERANC,
:MERANC,
:MERANC
DO
BEGIN
SUSPEND;
END
END
y para sorpresa compila, Al ejecutarlo devuelve unos resultados, ilógicos pero devuelve, por ej….
CREATE TABLE TAB_MERCANCI (
MERREF NUMSMA NOT NULL,
MERDET VARC50,
MERMED VARC20,
MERLAR NUMDEC,
MERANC NUMDEC,
MERALT NUMDEC,
MERCAN NUMINT,
TIPREF NUMSMA)
Con datos
1, ‘CUALQUIER COSA’, ‘CMS’, 20.00, 15.00, 10.00, 1000, 1
Produce como resultado
CMS, NULL, 1000.00, NULL, NULL
Pienso que al producir como resultado pocas variables se detecta a ojo el error, pero si hablamos de 50, 80 creo sería algo complicado detectar donde repetimos la variable y los resultados que nos arroja no serían los correctos…
A todas luces el error es de quien programa ya que es quien repite la variable, sin embargo pienso que tal hecho podría ser detectable en tiempo de compilación.
Esto tiene alguna explicación o en algunos casos un uso lógico, o definitivamente se podría interpretar como un bug…?
Utilizo la versión 2.5.5.26952
Saludos gracias por sus comentarios.
wrov
Feb 08, 2017 @ 12:39:51
Tienes razón, hice la prueba y compila. Y es cierto, no debería compilar. Postearé lo que considero un bug en el foro de los desarrolladores de Firebird.
Saludos.
Walter.
marco antonio Gonzalez
Ago 21, 2018 @ 12:47:50
Hola espero me puedan ayudar, un procedimiento lo mando a llamar con la siguiente consulta select * from procedure(@variable) pero lo que requiero es que el valor de la variablre sea un campo de una tabla, algo asi
select * from procedure(select ID_articulo from articulos) claro que de esta forma me manda error, como lo pudiera hacer, que el argumento del procedimiento se el campo de una tabla ?
wrov
Ago 21, 2018 @ 12:58:18
Para que puedas hacer lo que quieres, necesitas que el stored procedure sea seleccionable. O sea, que tenga el comando SUSPEND en su código fuente.
Luego, debes usar doble paréntesis, y luego, asegurarte que el SELECT interno devuelva una sola fila y una sola columna.
Saludos.
Walter.
marco antonio Gonzalez
Ago 21, 2018 @ 13:11:23
si, el procedere tiene SUSPEND en su código ,y el select interno me devuelve varios valores y es que lo necesito así para que casa valor del select interno lo tome el procedimiento y me de el resultado de cada valor del select interno, esto como pudiera hacerse ?
marco antonio Gonzalez
Ago 21, 2018 @ 13:22:33
Para poner mas claro el ejemplo el procedure me calcula el costo del articulo por lo que me pide el id del arituculo para calcularlo , pero quiero pasarle al procedimiento los id de todos mis aritulos para que me devuelva el costo de todos los articulos
select Costo_arituculo from procedure_calculo_costo (@IDarituculo)
VICKY
Dic 26, 2019 @ 16:17:03
Hola, necesito que un sp salga cuando no cumpla una condicion en in if y me mande variable de salida,
no se si me explico bien, tengo varios if en mi sp y quiero q si esta bien ejecute el otro if, sino q salga y me mande los parametros de salida que yo le asigne.
IF EXISTS (SELECT ‘0’
FROM t_cat_archive
WHERE t_cat_archive.Name = i_name_archive
and t_cat_archive.id_mandante = i_mandante)
THEN
«que salga y me mande unos parametros y que no siga»
END IF;
/*Se valida que exista el empleado */
IF EXISTS (SELECT ‘0’
FROM T_CAT_EMPLOYEE
WHERE T_CAT_EMPLOYEE.Id_employee = i_emplid
and T_CAT_EMPLOYEE.id_mandante = i_mandante)
THEN
select ‘ok’;
else
«que salga y me mande unos parametros y que no siga»
end if;
/*Se valida que no exista otra fecha con el mismo horario */
IF EXISTS (SELECT ‘0’
FROM t_db_rs.t_recording_sheet
WHERE Id_employee = i_emplid
and Date = i_fecha AND
((start_time BETWEEN i_timeI AND i_timeF)
OR (Final_hour BETWEEN i_timeI AND i_timeF)
OR (i_timeI BETWEEN start_time AND Final_hour))
and t_recording_sheet.id_mandante = i_mandante)
THEN
«que salga y me mande unos parametros y que no siga»
else
select ‘ok’;
end if;
Yvan Acosta (YAcosta)
Ene 22, 2020 @ 16:14:35
Hola estimado Walter, volviendo a los años y hace mucho q no toco esto y ando oxidado que quizá por ello no veo el error, me sale error de parsing en este codigo:
CREATE PROCEDURE OBT_COST(pFecha Date, pMPR_ID Integer)
RETURNS(Costo DOUBLE PRECISION)
AS DECLARE VARIABLE miCosto DOUBLE PRECISION;
BEGIN Select first 1 tval.tval_cost_usd
From TVAL where tval.tval_mpr_id = :pMPR_ID and
Cast(TVAL.tval_fdma as date) <= :pFecha)
Into :miCosto;
IF miCosto is null then Costo = 0 else Costo = miCosto);
END;
Quiero obtener un numero double de la tabla TVAL dando la fecha y el id del producto
Gracias doc
Yvan Acosta (YAcosta)
Ene 22, 2020 @ 18:24:03
Ya esta. Cometi varios errores:
1.- Hay un cierre de parentesis
2.- en el Into a miCosto le falta los :
Igual cambie el codigo por esto:
CREATE PROCEDURE OBT_COST(pFecha Date, pMPR_ID Integer)
RETURNS(
Costo TYPE OF COLUMN tval.tval_cost_usd)
AS
DECLARE VARIABLE miCosto TYPE OF COLUMN tval.tval_cost_usd;
BEGIN
Select first 1 tval.tval_cost_usd
From TVAL
where tval.tval_mpr_id = :pMPR_ID and
Cast(TVAL.tval_fdma as date) <= :pFecha
Into :Costo;
IF Costo is null then Costo = 0;
END;
Pero me marca error en Costo de la tercera linea
wrov
Ene 22, 2020 @ 18:36:06
Hola Yván
Debes escribir la condición del IF dentro de paréntesis:
IF (COSTO IS NULL) THEN
COSTO = 0;
También podrías escribir:
COSTO = COALESCE(COSTO, 0);
Saludos.
Walter.
Yvan Acosta (YAcosta)
Ene 22, 2020 @ 18:47:57
Hola amigo Walter gracias por responder. Hice el cambio pero me marca error en Column.
Adjunto captura de pantalla aqui: https://i.snipboard.io/2HyUz1.jpg
Yvan Acosta (YAcosta)
Ene 22, 2020 @ 18:56:11
Listo, ya paso, quite el TYPE OF COLUMN que no se porque razon no funca bien, Asi que puse directamente el tipo de dato quedando asi:
CREATE PROCEDURE OBT_COST(pFecha Date, pMPR_ID Integer)
RETURNS(
Costo DOUBLE PRECISION)
AS
DECLARE VARIABLE miCosto DOUBLE PRECISION;
BEGIN
Select first 1 tval.tval_cost_usd
From TVAL
where tval.tval_mpr_id = :pMPR_ID and
Cast(TVAL.tval_fdma as date) <= :pFecha
Into
:Costo;
Costo = COALESCE(Costo, 0);
END;
Y ya funciona.
Muchas gracias
hzuniga
Abr 20, 2020 @ 14:42:23
Buenas tardes..me podrías hacer el favor de aclararme algo..Como hago para que procedimiento de una actualizacion( update) me devuelva en nro d efilas afectadas que me pide excecutenoquery
gracais
Luisin XD
May 09, 2020 @ 15:45:02
hola, alguien me podría ayudar a crear una tabla mediante procedimientos almacenados
wrov
May 09, 2020 @ 20:58:11
En general no es aconsejable hacer eso. Se la considera muy mala práctica y con mucha razón, ya que al momento de escribir el código fuente el Firebird no sabe nada de nada de ella y por lo tanto no puede marcarte los errores que cometas.
De todas maneras, hay algunos artículos en este blog que muestran como hacerlo. Búscalos en la categoría «Stored procedures y triggers»
Saludos.
Walter.