Variable en cursor o Use en Procedure

04/03/2004 - 19:23 por Juan José Pinero | Informe spam
Hola Grupo,

Estoy haciendo un procedure y necesito abrir un cursor (perdonad los
detractores de los cursores, pero el fín justifica los medios) que apunte a
una de las 5 Bases de datos de que dispongo(BD1, BD2, BD3, BD4 y BD5). Al
procedure le paso la variable @BBDD sobre la que quiero realizar la
consulta.

Opción 1:
Use BD3

El problema es que se produce un error que informa que no se puede
utilizar Use en procedure

Opción 2:
Declare @MiTabla nvarchar(100)
Set @MiTabla = '[' + @BBDD + '].[dbo].[MiTablaComun]'
Declare MiCursor CURSOR FOR

SELECT *FROM @MiTabla
OPEN MiCursor

En este caso me dice que debo declarar la variable @MiTabla


No entiendo qué pasa. ¿Qué estoy haciendo mal?

Gracias de antemano.

Preguntas similare

Leer las respuestas

#11 Juan José Pinero
05/03/2004 - 19:48 | Informe spam
Gracias Maximiliano, Ulises y Javier.

La solución que me dabais tanto Maximiliano como Javier eran viables, si
bien me complicaban bastante al tener que crear las Vistas en todas las
Bases de Datos.
Ulises, tu solución, no he tenido tiempo de probarla, aunque creo que
también sería viable.
Finalmente adopté la opción de generar SQL dinámico en el procedure
declarando el cursor dentro del string que paso a sp_executesql

y . sorpresa!!:

Probé la solución que dabais Maximiliano y Javier (aplicando UNION ) sobre
una única Base de Datos y la solución de Sql dinámico con cursor (como
finalmente lo he dejado). Pues bién, sobre un tiempo de ejecución de 20
segundos que tarda la solución de UNION (sin cursor), la opción con Cursor
le gana por 5 segundos (tarda 15 segundos). Así que, pese a todo no hay que
tener tanto miedo a los cursores. Ahora bien, me anoto (bien a mano) vuestra
solución que será tenida en cuenta en futuros desarrollos. Por cierto
Javier, muy inteligente tu solución, y a la tabla temporal la he llamado
TMP_666 ;-)

Gracias por todo

Y saludos,



"Juan José Pinero" escribió en el mensaje
news:c28268$f71$
Disculpa las molestias Maximiliano.

El problema es el siguiente:

Tengo 5 bases de datos de producción. Cada una se ocupa de una parte del
negocio, aunque la estructura de las BBDD es idéntica.

Me solicitan que genere de forma automática y diariamente un fichero de
texto sobre los pedidos de compras con el formato siguiente:


Pedido1.NºPedido Pedido1.Proveedor Pedido1.TotalUds Pedido1.TotalImpore
Pedido1.Articulo1 Pedido1.UnidadesArticulo Pedido1.ImporteArticulo
Pedido1.Articulo2 Pedido1.UnidadesArticulo Pedido1.ImporteArticulo
Pedido1.Articulo3 Pedido1.UnidadesArticulo Pedido1.ImporteArticulo
.
.
Pedido1.ArticuloN Pedido1.UnidadesArticulo Pedido1.ImporteArticulo
Pedido2.NºPedido Pedido2.Proveedor Pedido2.TotalUds Pedido2.TotalImpore
Pedido2.Articulo1 Pedido2.UnidadesArticulo Pedido2.ImporteArticulo
Pedido2.Articulo2 Pedido2.UnidadesArticulo Pedido2.ImporteArticulo
Pedido2.Articulo3 Pedido2.UnidadesArticulo Pedido2.ImporteArticulo
.
.
Pedido2.ArticuloN Pedido2.UnidadesArticulo Pedido2.ImporteArticulo
.

.
PedidoN.NºPedido Pedido2.Proveedor PedidoN.TotalUds PedidoN.TotalImpore
PedidoN.Articulo1 PedidoN.UnidadesArticulo PedidoN.ImporteArticulo
PedidoN.Articulo2 PedidoN.UnidadesArticulo PedidoN.ImporteArticulo
PedidoN.Articulo3 PedidoN.UnidadesArticulo PedidoN.ImporteArticulo
.
.
PedidoN.ArticuloN PedidoN.UnidadesArticulo PedidoN.ImporteArticulo


Como ves es la típica estructura de cabecera detalle (una linea para la
cabecera y n lineas para el detalle)

Las líneas de cabecera son generadas por la Tabla1.
Las líneas de detalle son generadas por la Tabla2.

Pues bien, para resolver el problema he creado un procedure que crea una
tabla temporal:

CREATE PROCEDURE [MiProcedure] @BBDD as nvarchar(50)


CREATE TABLE #TablaTemp
(
Id int identity (1, 1) PRIMARY KEY
LineaFichero nvarchar(100)
)

Declaro un cursor

DECLARE MiCursor FOR

SELECT NPedido , Proveedor, TotalUds, TotalImporte, ClaveTabla2 FROM
[BD1].[dbo].Tabla1

OPEN MiCursor

FETCH NEXT FROM MiCursor into @a1, @a2, @a3, @a4, @a5

WHILE @@FETCH_STATUS=0
BEGIN
INSERT INTO #TablaTemp (LineaFichero) VALUES (@a1 + @a2 + @a3 + @a4)
INSERT INTO #TablaTemp (LineaFichero)
SELECT Articulo + UnidadesArticulo + ImporteArticulo FROM
[BD1].[dbo].Tabla2 WHERE ClaveTabla2=@a5

FETCH NEXT FROM MiCursor into @a1, @a2, @a3, @a4, @a5
END



De esta forma en la tabla #TablaTemp tengo las líneas ordenadas (por el
campo Id) como deben ser escritas en el fichero a generar.

La cuestión es que [BD1] debe ser variable , ya que la consulta la tengo


que
generar en las 5 bases de datos de producción, pasándole al procedure una
variable @BBDD, pero no veo la forma de hacerlo, ya que no puedo abrir el
Cursos con sp_executesql ni con execute, únicamente me lo permite con
SELECT.

Por otro lado intenté hacer un Use @BBDD, pero tampoco puedo, ya que


parece
que el uso de Use dentro de un procedure no está permitido.

En fin, que no sé como salir de aquí.

Saludos.









"Maximiliano D. A." <maxi_accotto[arroba]speedy[.]com[.]ar> escribió en el
mensaje news:Ofz1y#
> Esta bien y cual es el problema!! no te entiendo realmente!!
>
>
> Salu2
> Maxi
> Buenos Aires Argentina
> Desarrollador Microsoft 3 Estrellas .NET
> [Maxi_accotto[arroba]speedy[punto]com[punto]ar
> MSN:
>
>
> "Juan José Pinero" escribió en el mensaje
> news:c2805b$3qj$
> > Lo haría, pero la línea de cabera sólo puede tener campos de la


consulta
> de
> > cabecera y en las líneas de detalle sólo puede haber campos de la
consulta
> > de detalle.
> >
> > ¿Me puedes confirma la imposibilidad de declarar un cursor con Sql
> dinámico?
> >
> > Gracias de todas formas.
> >
> >
> >
> > Un saludo.
> >
> >
> >
> > "Maximiliano D. A." <maxi_accotto[arroba]speedy[.]com[.]ar> escribió


en
el
> > mensaje news:
> > > Bueno ahora has sido muy claro y eso me gusta!! como cosa linda es


que
> > > podemos sacar el cursor!!!
> > >
> > > Porque no intentas hacer algo asi como:
> > >
> > > Select tabla1.campos,tabla1..campos,tabla2.campos from tabla1 left
join
> > > (select campos from tabla2) tabla2 on
> > > tabla1.campo_id = tabla2.campoid
> > >
> > >
> > > esta es una forma que te puede servir, adaptalo a tus tablas.
> > >
> > > Cuando yo te hablo de sp_executesql es porque vi que querias hacer


un
> > select
> > > tipo asi:
> > >
> > > declare @mibase varchar(255)
> > >
> > > set @mibase ='maxi'
> > >
> > > Select * from @MIBASE.TABLA
> > >
> > > esto si no usas SqlDinamico no te funcionara :(
> > >
> > > Bye
> > >
> > > Salu2
> > > Maxi
> > > Buenos Aires Argentina
> > > Desarrollador Microsoft 3 Estrellas .NET
> > > [Maxi_accotto[arroba]speedy[punto]com[punto]ar
> > > MSN:
> > >
> > >
> > > "Juan José Pinero" escribió en el mensaje
> > > news:c27ue1$l3o$
> > > > Gracias por tu respuesta,
> > > >
> > > > No te he entendido bien, ¿te refieres a que abra el cursor
utilizando
> > > > sp_executesql?
> > > > En cuanto a abrir el cursor con sp_executesql ya lo he intentado,
> pero
> > me
> > > > dice que hay error de sintaxis cerca de sp_executesql.
> > > >
> > > > Esta es la cuestión por la que creo que no tengo más remedio que
> > utilizar
> > > > cursor en el procedure:
> > > >
> > > > Necesito ejecutar 2 consultas, las 2 devuelven varios registros.
Estas
> > > > consultas deberé poder realizarlas en cualquiera de las 5 bases de
> datos
> > > de
> > > > producción.
> > > >
> > > >
> > > > Consulta1 (Cabecera)
> > > > NºPedido, Proveedor, TotalUds, TotalImporte
> > > >
> > > > Consulta2 (Detalle)
> > > > Articulo, Uds, ImporteLinea
> > > >
> > > > Por cada registro de la Consulta1 obtendré varios registros de la
> > > Consulta2.
> > > >
> > > > El problema es que tengo que generar un fichero con el siguiente
> > formato:
> > > >
> > > > Consulta1.Registro1.NºPedido Consulta1.Registro1.Proveedor
> > > > Consulta1.Registro1.TotalUds Consulta1.Registro1.TotalImporte
> > > > Consulta2.Registro1.Articulo Consulta2.Registro1.Uds
> > > > Consulta2.Registro1.ImporteLinea
> > > > Consulta2.Registro2.Articulo Consulta2.Registro2.Uds
> > > > Consulta2.Registro2.ImporteLinea
> > > > Consulta2.Registro3.Articulo Consulta2.Registro3.Uds
> > > > Consulta2.Registro3.ImporteLinea
> > > > ..
> > > > ..
> > > > Consulta2.RegistroN.Articulo Consulta2.RegistroN.Uds
> > > > Consulta2.RegistroN.ImporteLinea
> > > >
> > > > Consulta1.Registro2.NºPedido Consulta1.Registro1.Proveedor
> > > > Consulta1.Registro1.TotalUds Consulta1.Registro1.TotalImporte
> > > > Consulta2.Registro1.Articulo Consulta2.Registro1.Uds
> > > > Consulta2.Registro1.ImporteLinea
> > > > Consulta2.Registro2.Articulo Consulta2.Registro2.Uds
> > > > Consulta2.Registro2.ImporteLinea
> > > > Consulta2.Registro3.Articulo Consulta2.Registro3.Uds
> > > > Consulta2.Registro3.ImporteLinea
> > > > .
> > > > .
> > > > Consulta2.RegistroN.Articulo Consulta2.RegistroN.Uds
> > > > Consulta2.RegistroN.ImporteLinea
> > > >
> > > >
> > > > Pues bien, con el cursor abro la Consulta1 y en una tabla temporal
voy
> > > > generando las líneas que necesito escribir al fichero en orden. No
> abro
> > > > cursor para la Consulta2, si no que hago un INSERT directamente en
la
> > > tabla
> > > > temporal filtrando con las claves que me devuelve el cursor de la
> > > > Consulta1.
> > > >
> > > > No conozco ninguna otra forma de resolver este problema sin


utilizar
> el
> > > > cursor.
> > > >
> > > >
> > > >
> > > > Saludos y Gracias,
> > > >
> > > >
> > > >
> > > >
> > > > "Maximiliano D. A." <maxi_accotto[arroba]speedy[.]com[.]ar>


escribió
> en
> > el
> > > > mensaje news:#qj$
> > > > > Deberias usar SqlDinamico si queres por variable pasar la BASE o
sea
> > > > > revisate en tus manuales el
> > > > >
> > > > > sp_executesql, esto podria serte util!!
> > > > >
> > > > > Ahora porque pensas usar un cursor? que necesitas hacer que no
> > > encontraste
> > > > > otra qie un cursor?
> > > > >
> > > > > Bye
> > > > >
> > > > >
> > > > > Salu2
> > > > > Maxi
> > > > > Buenos Aires Argentina
> > > > > Desarrollador Microsoft 3 Estrellas .NET
> > > > > [Maxi_accotto[arroba]speedy[punto]com[punto]ar
> > > > > MSN:
> > > > >
> > > > >
> > > > > "Juan José Pinero" escribió en el mensaje
> > > > > news:c27s7q$4o3$
> > > > > > Hola Grupo,
> > > > > >
> > > > > > Estoy haciendo un procedure y necesito abrir un cursor


(perdonad
> los
> > > > > > detractores de los cursores, pero el fín justifica los medios)
que
> > > > apunte
> > > > > a
> > > > > > una de las 5 Bases de datos de que dispongo(BD1, BD2, BD3, BD4


y
> > BD5).
> > > > Al
> > > > > > procedure le paso la variable @BBDD sobre la que quiero


realizar
> la
> > > > > > consulta.
> > > > > >
> > > > > > Opción 1:
> > > > > > Use BD3
> > > > > >
> > > > > > El problema es que se produce un error que informa que no


se
> > puede
> > > > > > utilizar Use en procedure
> > > > > >
> > > > > > Opción 2:
> > > > > > Declare @MiTabla nvarchar(100)
> > > > > > Set @MiTabla = '[' + @BBDD + '].[dbo].[MiTablaComun]'
> > > > > > Declare MiCursor CURSOR FOR
> > > > > >
> > > > > > SELECT *FROM @MiTabla
> > > > > > OPEN MiCursor
> > > > > >
> > > > > > En este caso me dice que debo declarar la variable


@MiTabla
> > > > > >
> > > > > >
> > > > > > No entiendo qué pasa. ¿Qué estoy haciendo mal?
> > > > > >
> > > > > > Gracias de antemano.
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > >
> > > > >
> > > > >
> > > > > Outgoing mail is certified Virus Free.
> > > > > Checked by AVG anti-virus system (http://www.grisoft.com).
> > > > > Version: 6.0.593 / Virus Database: 376 - Release Date:


20/02/2004
> > > > >
> > > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > > Outgoing mail is certified Virus Free.
> > > Checked by AVG anti-virus system (http://www.grisoft.com).
> > > Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
> > >
> > >
> >
> >
>
>
>
> Outgoing mail is certified Virus Free.
> Checked by AVG anti-virus system (http://www.grisoft.com).
> Version: 6.0.593 / Virus Database: 376 - Release Date: 20/02/2004
>
>


Respuesta Responder a este mensaje
#12 ulises
05/03/2004 - 20:51 | Informe spam
Juan,

Sería muy interesante conocer tus pruebas ya que hasta el
momento no había encontrado una prueba a favor del cursor,
en todo caso he realizado una prueba pequeña simulando tu
caso y probando dentro del mismo servidor para efectos de
no tener los ruidos de la transferencia a través de la
red :

CREATE TABLE pedido ( codigo int, descripcion char(20) )
go
CREATE TABLE detalle ( codigo int, secuencia int, glosa
char(30) )
go
INSERT INTO pedido VALUES ( 1, 'PEDIDO 1')
INSERT INTO pedido VALUES ( 2, 'PEDIDO 2')
INSERT INTO pedido VALUES ( 3, 'PEDIDO 3')
INSERT INTO pedido VALUES ( 4, 'PEDIDO 4')
INSERT INTO pedido VALUES ( 5, 'PEDIDO 5')
INSERT INTO pedido VALUES ( 6, 'PEDIDO 6')
go
INSERT INTO detalle VALUES (1, 1, 'PED1 -GLOSA1')
INSERT INTO detalle VALUES (1, 2, 'PED1 -GLOSA2')
INSERT INTO detalle VALUES (1, 3, 'PED1 -GLOSA3')
INSERT INTO detalle VALUES (1, 4, 'PED1 -GLOSA4')
INSERT INTO detalle VALUES (1, 5, 'PED1 -GLOSA5')
INSERT INTO detalle VALUES (1, 6, 'PED1 -GLOSA6')
INSERT INTO detalle VALUES (2, 1, 'PED2 -GLOSA1')
INSERT INTO detalle VALUES (2, 2, 'PED2 -GLOSA2')
INSERT INTO detalle VALUES (2, 3, 'PED2 -GLOSA3')
INSERT INTO detalle VALUES (3, 1, 'PED3 -GLOSA1')
INSERT INTO detalle VALUES (3, 2, 'PED3 -GLOSA2')
INSERT INTO detalle VALUES (4, 1, 'PED4 -GLOSA1')
INSERT INTO detalle VALUES (4, 2, 'PED4 -GLOSA2')
INSERT INTO detalle VALUES (4, 3, 'PED4 -GLOSA3')
INSERT INTO detalle VALUES (4, 4, 'PED4 -GLOSA4')
INSERT INTO detalle VALUES (4, 5, 'PED4 -GLOSA5')
INSERT INTO detalle VALUES (4, 6, 'PED4 -GLOSA6')
INSERT INTO detalle VALUES (5, 1, 'PED5 -GLOSA1')
INSERT INTO detalle VALUES (5, 2, 'PED5 -GLOSA2')
INSERT INTO detalle VALUES (5, 3, 'PED5 -GLOSA3')
INSERT INTO detalle VALUES (5, 4, 'PED5 -GLOSA4')
INSERT INTO detalle VALUES (6, 1, 'PED6 -GLOSA1')
INSERT INTO detalle VALUES (6, 2, 'PED6 -GLOSA2')
INSERT INTO detalle VALUES (6, 3, 'PED6 -GLOSA3')
go
PRINT 'Solo SELECT'
SELECT CURRENT_TIMESTAMP
go
SELECT codigo, 0 as secuencia, ( CAST(codigo as varchar
(10)) + descripcion) as cadena
FROM pedido
UNION ALL
SELECT codigo, secuencia, ( CAST(codigo as varchar(10)) +
glosa ) as cadena
FROM detalle
ORDER BY codigo, secuencia
go
SELECT CURRENT_TIMESTAMP
go
PRINT 'Uso de Cursor'
SELECT CURRENT_TIMESTAMP
go
CREATE TABLE #TablaTemp (Id int identity (1, 1) PRIMARY
KEY, LineaFichero nvarchar(100))
DECLARE @cod as int
DECLARE @des as char(20)
DECLARE @glo as char(30)
DECLARE MiCursor CURSOR FOR
SELECT codigo, descripcion FROM pedido
OPEN MiCursor
FETCH NEXT FROM MiCursor into @cod, @des
WHILE @@FETCH_STATUS=0
BEGIN
INSERT INTO #TablaTemp (LineaFichero) VALUES (CAST
(@cod as varchar(10)) + @des )
INSERT INTO #TablaTemp (LineaFichero)
SELECT ( CAST(codigo as varchar(10)) + glosa )
FROM detalle WHERE codigo = @cod
FETCH NEXT FROM MiCursor into @cod, @des
END
CLOSE MiCursor
DEALLOCATE MiCursor
SELECT LineaFichero FROM #TablaTemp ORDER BY Id
DROP TABLE #TablaTemp
go
SELECT CURRENT_TIMESTAMP
go

y me indicado que la solución con el UNION me ha demorado
0.017 segundos mientras que la de CURSOR 0.030; si aumento
la cantidad de registros a 192 pedidos y 768 detalles me
arroja un tiempo de 0.064 con el uso de UNION mientras que
con el CURSOR 0.297 segundos.

Otro tema a revisar es el uso de recursos que podriamos
medirlos con el Perfmon, pero eso lo dejo para el fin de
semana.

Saludos,
Ulises

...
Probé la solución que dabais Maximiliano y Javier


(aplicando UNION ) sobre
una única Base de Datos y la solución de Sql dinámico con


cursor (como
finalmente lo he dejado). Pues bién, sobre un tiempo de


ejecución de 20
segundos que tarda la solución de UNION (sin cursor), la


opción con Cursor
le gana por 5 segundos (tarda 15 segundos). Así que, pese


a todo no hay que
tener tanto miedo a los cursores. Ahora bien, me anoto


(bien a mano) vuestra
solución que será tenida en cuenta en futuros


desarrollos. Por cierto
Javier, muy inteligente tu solución, y a la tabla


temporal la he llamado
TMP_666 ;-)
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida