Ir al contenido


Foto

retornar un Recordset en un procedimiento almacenado.


  • Por favor identifícate para responder
16 respuestas en este tema

#1 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 13 abril 2014 - 03:47

Estoy haciendo algunas cosas en Firebird y me surge la duda.

Debo hacer un procedimiento almacenado que dado un criterio me devuelve el conjunto de filas coincidentes. ¿Cómo se hace en firebird?

Gracias.
  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 13 abril 2014 - 03:56

El truco está en una cláusula: SUSPEND. Ésta se emplea para ir moviéndose registro por registro y armar el conjunto de datos.
Te puedo recomendar las siguientes lecturas:
Lectura 1
Lectura 2
Lectura 3

La última está en español y explica bastante bien como entender el funcionamiento de los SP. Las dos anteriores, sobre todo la 2da, se centran más en la documentación.
Si te estás adentrando a Firebird, te recomiendo la lectura del documento Command Line, que forma parte de la documentación oficial.
No tengo un ejemplo a mano, pero en los enlaces verás unos cuantos.

Saludos,
  • 0

#3 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 13 abril 2014 - 04:47

veo que en el return debe declararse la lista de campos con su tipo respectivo que serán devueltos al invocar el SP. ¿Esto es absolutamente necesario? ¿Qué sucede si quiero encapsular en un mismo sp 3 consultas distintas?
  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 13 abril 2014 - 05:07

veo que en el return debe declararse la lista de campos con su tipo respectivo que serán devueltos al invocar el SP. ¿Esto es absolutamente necesario? ¿Qué sucede si quiero encapsular en un mismo sp 3 consultas distintas?

Cuando se trata justamente de un SP seleccionable, debe indicarse los parámetros de salida. De modo que cada vez que se encuentra una clásula SUPEND se devuelven los datos que actualmente se hayan pasado a estos parámetros.

Así es como funciona Firebird.
Respecto a lo que comentas de encapsular 3 consultas distintas no logro entenderte bien. ¿A que te refieres? Si me das un mejor panorama podría ver en como va la mano y si es que se puede hacer. En principio nada le impide a Firebird ejecutar varios selects en un mismo SP. Mientras se haya diseñado para colocar los resultados en las variables de salida y la correcta invocación a SUSPEND no hay problema alguno.

Saludos,
  • 0

#5 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 13 abril 2014 - 05:20

Respecto a lo que comentas de encapsular 3 consultas distintas no logro entenderte bien. ¿A que te refieres? Si me das un mejor panorama podría ver en como va la mano y si es que se puede hacer. En principio nada le impide a Firebird ejecutar varios selects en un mismo SP. Mientras se haya diseñado para colocar los resultados en las variables de salida y la correcta invocación a SUSPEND no hay problema alguno.

Saludos,


Con mucho gusto amigo.

Supongamos que tengo la entidad países cuyos atributos son Id, Nombre, Poblacion. Luego entonces en mi sistema tendré los siguientes requerimientos.

Devolver
1)  Id, Nombre y Población de los países registrados.
2) Dado un Id de país, el nombre correspondiente.
3) Dado un id de país la población correspondiente
4) dado un  id de país los atributos Nombre y Población.

Esta situación puedo resolverla con 4 Procedimientos almacenados dedicados cada uno a la función respectiva pero, ¿qué sucede si quiero encapsular en un solo SP las 4 consultas que devuelven campos diferentes?


  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 13 abril 2014 - 05:37

Solución creativa y sencilla:
Añade un parámetro de entrada más que te permita indicar el tipo de datos a devolver. Es decir, el típico parámetro de opción.
Cuando no se deba devolver un dato, simplemente se indica en el parámetro de salida algún valor que indique que no se cuenta con él, como por ejemplo 0 o un número negativo. Hasta creo incluso que es posible indicarle que sea NULL.

Saludos,
  • 0

#7 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 13 abril 2014 - 06:13

Solución creativa y sencilla:
Añade un parámetro de entrada más que te permita indicar el tipo de datos a devolver. Es decir, el típico parámetro de opción.
Cuando no se deba devolver un dato, simplemente se indica en el parámetro de salida algún valor que indique que no se cuenta con él, como por ejemplo 0 o un número negativo. Hasta creo incluso que es posible indicarle que sea NULL.

Saludos,


Pero de ser así entonces me obligaría a estar siempre devolviendo el mismo número de campos generando datos tráfico innecesario ¿no cres?
  • 0

#8 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 13 abril 2014 - 06:45

Pues si pero si se tiene en cuenta que esos casos son cuando ha de devolver un solo registro no me parece tan exagerada la pérdida por el tráfico.

Saludos,
  • 0

#9 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 13 abril 2014 - 07:04

Pues si pero si se tiene en cuenta que esos casos son cuando ha de devolver un solo registro no me parece tan exagerada la pérdida por el tráfico.

Saludos,


Claro, aunque no me parece que sea correcto devolver campos que no tienen que ver con la sentencia que se está ejecutando. Me parece que en lo que atañe a firebird es mejor usar Sps separados.
  • 0

#10 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 14 abril 2014 - 07:11

Saludos.

Creo que la solución propuesta por Delphius es la más indicada, solo devolver nulo los campos que para determinada consulta no sean necesarios, me parece que no sería mucha carga en la red.

Además con esto te evitas el tener tantos procedimientos para darle mantenimiento en caso de un cambio de estructura.

Suerte!!
  • 0

#11 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 14 abril 2014 - 07:41



Además con esto te evitas el tener tantos procedimientos para darle mantenimiento en caso de un cambio de estructura.

Suerte!!


Exacto amigo mio, esa es la idea de encapsular en un solo sp varias consultas.
  • 0

#12 Sergio

Sergio

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.092 mensajes
  • LocationMurcia, España

Escrito 15 abril 2014 - 03:07

Si quieres que devuelva un recordset, las columnas del recordset TIENEN que estar predefindas, no hay mas manera, igual que una tabla tiene 8 columnas siempre, no hay records de 3 y otros de 8, lo que haces es dejar los otros 5 campos a null y listo, pues aqui igual.

Lo que tu pides es mas de cubos de decision y esas cosas donde las columnas se gngeran dinamicamente (una columna por año existente en los datos y esas cosas), pero eso es bastante mas avanzado y complejro, necesitas objetos externos a delphi para manejar ese tipo de cosas (busca por decisioncube por google).
  • 0

#13 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 15 abril 2014 - 07:22

Si quieres que devuelva un recordset, las columnas del recordset TIENEN que estar predefindas, no hay mas manera, igual que una tabla tiene 8 columnas siempre, no hay records de 3 y otros de 8, lo que haces es dejar los otros 5 campos a null y listo, pues aqui igual.


Entiendo amigo, la idea de no tener que especificarlas me viene de otras bases de datos que no lo exigen. Por ello preguntaba si había alguna forma en Firebird de no indicarlas. Realmente mis conocimientos de firebird sin pocos.
  • 0

#14 Fenareth

Fenareth

    Advanced Member

  • Administrador
  • 3.486 mensajes
  • LocationMexico City

Escrito 15 abril 2014 - 08:13


Si quieres que devuelva un recordset, las columnas del recordset TIENEN que estar predefindas, no hay mas manera, igual que una tabla tiene 8 columnas siempre, no hay records de 3 y otros de 8, lo que haces es dejar los otros 5 campos a null y listo, pues aqui igual.


Entiendo amigo, la idea de no tener que especificarlas me viene de otras bases de datos que no lo exigen. Por ello preguntaba si había alguna forma en Firebird de no indicarlas. Realmente mis conocimientos de firebird sin pocos.


Es verdad, el hacer un select * from tabla en un stored procedure en Firebird es mucho más complejo que hacerlo en Oracle por ejemplo (que es donde tengo experiencia), donde declaras un cursor y devuelve en automático todas las columnas del select. Al final es posible hacerlo en Firebird, pero si se vuelve más tedioso...

Saludox ! :)
  • 0

#15 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 15 abril 2014 - 08:50

Supongamos que tengo la entidad países cuyos atributos son Id, Nombre, Poblacion. Luego entonces en mi sistema tendré los siguientes requerimientos.

Devolver
1)  Id, Nombre y Población de los países registrados.
2) Dado un Id de país, el nombre correspondiente.
3) Dado un id de país la población correspondiente
4) dado un  id de país los atributos Nombre y Población.

Esta situación puedo resolverla con 4 Procedimientos almacenados dedicados cada uno a la función respectiva pero, ¿qué sucede si quiero encapsular en un solo SP las 4 consultas que devuelven campos diferentes?



Para este problema que planteas no hay mayores inconvenientes para resolverlo, por supuesto que puedes encapsular todo en un mismo procedimiento, mira el código del sp:


delphi
  1. SET TERM ^ ;
  2.  
  3. create or alter procedure TEST_PROCEDURE
  4. returns (
  5.     ID integer,
  6.     NOMBRE varchar(10),
  7.     POBLACION integer)
  8. as
  9. begin
  10. FOR SELECT ID, NOMBRE, POBLACION FROM PAISES INTO :id, :nombre,  :POBLACION  DO
  11.   suspend;
  12. end^
  13.  
  14. SET TERM ; ^



Ahora las llamadas:


delphi
  1. // caso 1
  2. SELECT * FROM TEST_PROCEDURE
  3.  
  4. //Caso 2
  5. SELECT NOMBRE FROM TEST_PROCEDURE WHERE ID = :ID
  6.  
  7. //Caso 3
  8. SELECT POBALCION FROM TEST_PROCEDURE WHERE ID = :ID
  9.  
  10. //Caso 4
  11. SELECT NOMBRE, POBALCION FROM TEST_PROCEDURE WHERE ID = :ID
  12.  



Saludos.
  • 0

#16 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 15 abril 2014 - 09:14


Para este problema que planteas no hay mayores inconvenientes para resolverlo, por supuesto que puedes encapsular todo en un mismo procedimiento, mira el código del sp:


Excelente ejemplo. Muchas gracias por el código amigo.
  • 0

#17 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 15 abril 2014 - 09:59


Supongamos que tengo la entidad países cuyos atributos son Id, Nombre, Poblacion. Luego entonces en mi sistema tendré los siguientes requerimientos.

Devolver
1)  Id, Nombre y Población de los países registrados.
2) Dado un Id de país, el nombre correspondiente.
3) Dado un id de país la población correspondiente
4) dado un  id de país los atributos Nombre y Población.

Esta situación puedo resolverla con 4 Procedimientos almacenados dedicados cada uno a la función respectiva pero, ¿qué sucede si quiero encapsular en un solo SP las 4 consultas que devuelven campos diferentes?



Para este problema que planteas no hay mayores inconvenientes para resolverlo, por supuesto que puedes encapsular todo en un mismo procedimiento, mira el código del sp:


delphi
  1. SET TERM ^ ;
  2.  
  3. create or alter procedure TEST_PROCEDURE
  4. returns (
  5.     ID integer,
  6.     NOMBRE varchar(10),
  7.     POBLACION integer)
  8. as
  9. begin
  10. FOR SELECT ID, NOMBRE, POBLACION FROM PAISES INTO :id, :nombre,  :POBLACION  DO
  11.   suspend;
  12. end^
  13.  
  14. SET TERM ; ^



Ahora las llamadas:


delphi
  1. // caso 1
  2. SELECT * FROM TEST_PROCEDURE
  3.  
  4. //Caso 2
  5. SELECT NOMBRE FROM TEST_PROCEDURE WHERE ID = :ID
  6.  
  7. //Caso 3
  8. SELECT POBALCION FROM TEST_PROCEDURE WHERE ID = :ID
  9.  
  10. //Caso 4
  11. SELECT NOMBRE, POBALCION FROM TEST_PROCEDURE WHERE ID = :ID
  12.  



Saludos.

¿Podés creerlo que se me escapaba ese "pequeño" detalle? Llevo tanto tiempo alejado de la programación que ya se me olvidada que un SP seleccionable actúa como una tabla normal y es posible indicarle que campos extraer.

Saludos,
  • 0




IP.Board spam blocked by CleanTalk.