Como evitar cursores

14/01/2008 - 20:03 por Alr | Informe spam
Tengo una tabla Sql como de 60000 registros, donde viene un numero de
cliente, fecha, litros vendidos e importe de la venta,
esta informacion la quiero pasar a otra tabla que tiene una estructura del
tipo cvecliente, imp01I, lts01I, dsc01I, imp02I,
lts02I, des02I, imp01F, lts01F, des01F, imp02F, lts02F, des02F, etc, etc.,
donde imp01I es Importe del mes 01(Enero) y
del ano1 (primer ano a comparar) -> imp=Importe, 01=Enero, I=Ano Inicial del
comparativo(2006), imp=Importe, 01=Enero,
F=Ano Final del comparativo(2007).
Esto con el fin de hacer un reporte comparativo por ano, ejemplo: ventas por
cliente del ano 2006 vs 2007, desglosado por mes.
Bueno esto entre otros datos que se manejan, pero la idea es no tener que
hacer cursores, pero no se si esto se pueda hacer de
otra forma, y evitar los cursores. Lo que hago es lo siguiente:
Nota: las variables que no estan decaradas aqui abajo, le llegan al SP, por
lo que este codigo es solo ilustrativo.

DECLARE @Fechax AS DATETIME
DECLARE @CveGrupo AS INT
DECLARE @CveClien AS INT
DECLARE @NomClien AS VARCHAR(50)
DECLARE @Importe AS MONEY
DECLARE @CanSurti AS MONEY
DECLARE @Descuent AS MONEY
DECLARE CliMes_Cursor1 CURSOR
FOR SELECT FECHAX, CVEGRUPO, CVECLIEN, NOMCLIEN, IMPORTE, CANSURTI, DESCUENT
FROM RS_CLIMESD
WHERE (USUARIO = @pUsuari) AND (NOMREP = @pNomRep) AND (FECHAINT >=
@pFhI_1) AND (FECHAINT <= @pFhF_1)
ORDER BY CVEGRUPO, CVECLIEN
OPEN CliMes_Cursor1
FETCH NEXT FROM CliMes_Cursor1 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
WHILE @@FETCH_STATUS = 0
BEGIN
IF MONTH(@Fechax) = 1 -- ENERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien) AND
(USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01I, LTS01I, DES01I, POR01I, IMP02I,
LTS02I, DES02I, POR02I, IMP03I, LTS03I, DES03I, POR03I, IMP04I, LTS04I,
DES04I, POR04I, IMP05I, LTS05I, DES05I, POR05I, IMP06I, LTS06I, DES06I,
POR06I, IMP07I, LTS07I, DES07I, POR07I, IMP08I, LTS08I, DES08I, POR08I,
IMP09I, LTS09I, DES09I, POR09I, IMP10I, LTS10I, DES10I, POR10I, IMP11I,
LTS11I, DES11I, POR11I, IMP12I, LTS12I, DES12I, POR12I)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, @Importe, @CanSurti, @Descuent, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP01I = IMP01I + @Importe, LTS01I = LTS01I +
@CanSurti, DES01I = DES01I + @Descuent, POR01I = POR01I + 0
END
END
IF MONTH(@Fechax) = 2 -- FEBRERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien) AND
(USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01I, LTS01I, DES01I, POR01I, IMP02I,
LTS02I, DES02I, POR02I, IMP03I, LTS03I, DES03I, POR03I, IMP04I, LTS04I,
DES04I, POR04I, IMP05I, LTS05I, DES05I, POR05I, IMP06I, LTS06I, DES06I,
POR06I, IMP07I, LTS07I, DES07I, POR07I, IMP08I, LTS08I, DES08I, POR08I,
IMP09I, LTS09I, DES09I, POR09I, IMP10I, LTS10I, DES10I, POR10I, IMP11I,
LTS11I, DES11I, POR11I, IMP12I, LTS12I, DES12I, POR12I)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, 0, 0, 0, 0, @Importe, @CanSurti, @Descuent, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP02I = IMP02I + @Importe, LTS02I = LTS02I +
@CanSurti, DES02I = DES02I + @Descuent, POR02I = POR02I + 0
END
END
FETCH NEXT FROM CliMes_Cursor1 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
END
CLOSE CliMes_Cursor1
DEALLOCATE CliMes_Cursor1

IF @pCompar = 'S' -- Variable que le llega al SP para saber si es un
comparativo.
BEGIN
DECLARE CliMes_Cursor2 CURSOR
FOR SELECT FECHAX, CVEGRUPO, CVECLIEN, NOMCLIEN, IMPORTE, CANSURTI,
DESCUENT
FROM RS_CLIMESD
WHERE (USUARIO = @pUsuari) AND (NOMREP = @pNomRep) AND (FECHAINT

= @pFhI_2) AND (FECHAINT <= @pFhF_2)


ORDER BY CVEGRUPO, CVECLIEN
OPEN CliMes_Cursor2
FETCH NEXT FROM CliMes_Cursor2 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
SET @Contad = 0
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Contad = @Contad + 1
PRINT @Contad
IF MONTH(@Fechax) = 1 -- ENERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien)
AND (USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01F, LTS01F, DES01F, POR01F, IMP02F,
LTS02F, DES02F, POR02F, IMP03F, LTS03F, DES03F, POR03F, IMP04F, LTS04F,
DES04F, POR04F, IMP05F, LTS05F, DES05F, POR05F, IMP06F, LTS06F, DES06F,
POR06F, IMP07F, LTS07F, DES07F, POR07F, IMP08F, LTS08F, DES08F, POR08F,
IMP09F, LTS09F, DES09F, POR09F, IMP10F, LTS10F, DES10F, POR10F, IMP11F,
LTS11F, DES11F, POR11F, IMP12F, LTS12F, DES12F, POR12F)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, @Importe, @CanSurti, @Descuent, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP01F = IMP01F + @Importe, LTS01F = LTS01F +
@CanSurti, DES01F = DES01F + @Descuent, POR01F = POR01F + 0
END
END
IF MONTH(@Fechax) = 2 -- FEBRERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien)
AND (USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01F, LTS01F, DES01F, POR01F, IMP02F,
LTS02F, DES02F, POR02F, IMP03F, LTS03F, DES03F, POR03F, IMP04F, LTS04F,
DES04F, POR04F, IMP05F, LTS05F, DES05F, POR05F, IMP06F, LTS06F, DES06F,
POR06F, IMP07F, LTS07F, DES07F, POR07F, IMP08F, LTS08F, DES08F, POR08F,
IMP09F, LTS09F, DES09F, POR09F, IMP10F, LTS10F, DES10F, POR10F, IMP11F,
LTS11F, DES11F, POR11F, IMP12F, LTS12F, DES12F, POR12F)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, 0, 0, 0, 0, @Importe, @CanSurti, @Descuent, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP02F = IMP02F + @Importe, LTS02F = LTS02F +
@CanSurti, DES02F = DES02F + @Descuent, POR02F = POR02F + 0
END
END
FETCH NEXT FROM CliMes_Cursor2 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
END
CLOSE CliMes_Cursor2
DEALLOCATE CliMes_Cursor2
END


Y asi con todos los meses, agradeceria cualaquier ayuda.
Me disculpo si es escesivo el codigo que envio de ejemplo.
Espero que haber podido explicar mi problema.

Gracias y saludos.
 

Leer las respuestas

#1 qwalgrande
15/01/2008 - 08:19 | Informe spam
Hola.

Intenta lo siguiente:
- Prepara una consulta con los datos de las ventas por cliente de un mes,
por ejemplo, Enero de 2006. Sin entrar en detalles, entre otras cosas tendrás
un filtro de fechas, una agrupación por cliente y una suma de cantidades.
- Modifica esa consulta, cambia el filtro de fechas de un mes por las de
todo el 2006. En los campos de suma de cantidades, sustituye el campo que se
suma por un "case" parecido a este:
...
IMPORTE_ENERO = sum(case when [fechaint] >= '20060101' and [fechaint] <=
'20060131' then [IMPORTE] else 0 end),
IMPORTE_FEBRERO = sum(case when [fechaint] >= '20060201' and [fechaint] <=
'20060228' then [IMPORTE] else 0 end),
...
- Lo mismo para todos los meses. He puesto fechas constantes, podrían ser
calculadas. Con ello tendríamos ya las ventas de 2006 desglosadas por meses.
- Prepara otra consulta igual, pero para el 2007.
- Une ambas consultas por un full join (habrá clientes que estaban en un año
y no en otro y los querrás ver todos, seleccionando los campos que te
interese más ver y realizando las comparaciones oportunas:

select isnull(V2006.Cliente, V2007.Cliente) as Cliente, V2006.Importe_Enero
as VentasEnero2006, V2007.Importe_Enero as VentasEnero2007,
from ([CONSULTA QUE HE PREPARADO PARA 2006]) V2006 full join ([CONSULTA QUE
HE PREPARADO PARA 2007])
on V2006.Cliente = V2007.Cliente

- Por supuesto, tendrás que refinarlo mucho, pero es muy posible que así
evites tener que usar el cursor.

Alberto López Grande

qwalgrande


"Alr" wrote:

Tengo una tabla Sql como de 60000 registros, donde viene un numero de
cliente, fecha, litros vendidos e importe de la venta,
esta informacion la quiero pasar a otra tabla que tiene una estructura del
tipo cvecliente, imp01I, lts01I, dsc01I, imp02I,
lts02I, des02I, imp01F, lts01F, des01F, imp02F, lts02F, des02F, etc, etc.,
donde imp01I es Importe del mes 01(Enero) y
del ano1 (primer ano a comparar) -> imp=Importe, 01=Enero, I=Ano Inicial del
comparativo(2006), imp=Importe, 01=Enero,
F=Ano Final del comparativo(2007).
Esto con el fin de hacer un reporte comparativo por ano, ejemplo: ventas por
cliente del ano 2006 vs 2007, desglosado por mes.
Bueno esto entre otros datos que se manejan, pero la idea es no tener que
hacer cursores, pero no se si esto se pueda hacer de
otra forma, y evitar los cursores. Lo que hago es lo siguiente:
Nota: las variables que no estan decaradas aqui abajo, le llegan al SP, por
lo que este codigo es solo ilustrativo.

DECLARE @Fechax AS DATETIME
DECLARE @CveGrupo AS INT
DECLARE @CveClien AS INT
DECLARE @NomClien AS VARCHAR(50)
DECLARE @Importe AS MONEY
DECLARE @CanSurti AS MONEY
DECLARE @Descuent AS MONEY
DECLARE CliMes_Cursor1 CURSOR
FOR SELECT FECHAX, CVEGRUPO, CVECLIEN, NOMCLIEN, IMPORTE, CANSURTI, DESCUENT
FROM RS_CLIMESD
WHERE (USUARIO = @pUsuari) AND (NOMREP = @pNomRep) AND (FECHAINT >=
@pFhI_1) AND (FECHAINT <= @pFhF_1)
ORDER BY CVEGRUPO, CVECLIEN
OPEN CliMes_Cursor1
FETCH NEXT FROM CliMes_Cursor1 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
WHILE @@FETCH_STATUS = 0
BEGIN
IF MONTH(@Fechax) = 1 -- ENERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien) AND
(USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01I, LTS01I, DES01I, POR01I, IMP02I,
LTS02I, DES02I, POR02I, IMP03I, LTS03I, DES03I, POR03I, IMP04I, LTS04I,
DES04I, POR04I, IMP05I, LTS05I, DES05I, POR05I, IMP06I, LTS06I, DES06I,
POR06I, IMP07I, LTS07I, DES07I, POR07I, IMP08I, LTS08I, DES08I, POR08I,
IMP09I, LTS09I, DES09I, POR09I, IMP10I, LTS10I, DES10I, POR10I, IMP11I,
LTS11I, DES11I, POR11I, IMP12I, LTS12I, DES12I, POR12I)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, @Importe, @CanSurti, @Descuent, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP01I = IMP01I + @Importe, LTS01I = LTS01I +
@CanSurti, DES01I = DES01I + @Descuent, POR01I = POR01I + 0
END
END
IF MONTH(@Fechax) = 2 -- FEBRERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien) AND
(USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01I, LTS01I, DES01I, POR01I, IMP02I,
LTS02I, DES02I, POR02I, IMP03I, LTS03I, DES03I, POR03I, IMP04I, LTS04I,
DES04I, POR04I, IMP05I, LTS05I, DES05I, POR05I, IMP06I, LTS06I, DES06I,
POR06I, IMP07I, LTS07I, DES07I, POR07I, IMP08I, LTS08I, DES08I, POR08I,
IMP09I, LTS09I, DES09I, POR09I, IMP10I, LTS10I, DES10I, POR10I, IMP11I,
LTS11I, DES11I, POR11I, IMP12I, LTS12I, DES12I, POR12I)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, 0, 0, 0, 0, @Importe, @CanSurti, @Descuent, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP02I = IMP02I + @Importe, LTS02I = LTS02I +
@CanSurti, DES02I = DES02I + @Descuent, POR02I = POR02I + 0
END
END
FETCH NEXT FROM CliMes_Cursor1 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
END
CLOSE CliMes_Cursor1
DEALLOCATE CliMes_Cursor1

IF @pCompar = 'S' -- Variable que le llega al SP para saber si es un
comparativo.
BEGIN
DECLARE CliMes_Cursor2 CURSOR
FOR SELECT FECHAX, CVEGRUPO, CVECLIEN, NOMCLIEN, IMPORTE, CANSURTI,
DESCUENT
FROM RS_CLIMESD
WHERE (USUARIO = @pUsuari) AND (NOMREP = @pNomRep) AND (FECHAINT
>= @pFhI_2) AND (FECHAINT <= @pFhF_2)
ORDER BY CVEGRUPO, CVECLIEN
OPEN CliMes_Cursor2
FETCH NEXT FROM CliMes_Cursor2 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
SET @Contad = 0
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Contad = @Contad + 1
PRINT @Contad
IF MONTH(@Fechax) = 1 -- ENERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien)
AND (USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01F, LTS01F, DES01F, POR01F, IMP02F,
LTS02F, DES02F, POR02F, IMP03F, LTS03F, DES03F, POR03F, IMP04F, LTS04F,
DES04F, POR04F, IMP05F, LTS05F, DES05F, POR05F, IMP06F, LTS06F, DES06F,
POR06F, IMP07F, LTS07F, DES07F, POR07F, IMP08F, LTS08F, DES08F, POR08F,
IMP09F, LTS09F, DES09F, POR09F, IMP10F, LTS10F, DES10F, POR10F, IMP11F,
LTS11F, DES11F, POR11F, IMP12F, LTS12F, DES12F, POR12F)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, @Importe, @CanSurti, @Descuent, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP01F = IMP01F + @Importe, LTS01F = LTS01F +
@CanSurti, DES01F = DES01F + @Descuent, POR01F = POR01F + 0
END
END
IF MONTH(@Fechax) = 2 -- FEBRERO
BEGIN
IF NOT EXISTS(SELECT * FROM RS_CLIMESE WHERE (CVECLIEN = @CveClien)
AND (USUARIO = @pUsuari) AND (NOMREP = @pNomRep))
BEGIN
INSERT INTO RS_CLIMESE (USUARIO, NOMREP, FHAINI, FHAFIN, CVEGRUPO,
CVECLIEN, NOMCLIEN, TIPVENTA, IMP01F, LTS01F, DES01F, POR01F, IMP02F,
LTS02F, DES02F, POR02F, IMP03F, LTS03F, DES03F, POR03F, IMP04F, LTS04F,
DES04F, POR04F, IMP05F, LTS05F, DES05F, POR05F, IMP06F, LTS06F, DES06F,
POR06F, IMP07F, LTS07F, DES07F, POR07F, IMP08F, LTS08F, DES08F, POR08F,
IMP09F, LTS09F, DES09F, POR09F, IMP10F, LTS10F, DES10F, POR10F, IMP11F,
LTS11F, DES11F, POR11F, IMP12F, LTS12F, DES12F, POR12F)
VALUES(@pUsuari, @pNomRep, @FhaIni, @FhaFin, @CveGrupo, @CveClien,
@NomClien, @pTipVta, 0, 0, 0, 0, @Importe, @CanSurti, @Descuent, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
END
ELSE
BEGIN
UPDATE RS_CLIMESE SET IMP02F = IMP02F + @Importe, LTS02F = LTS02F +
@CanSurti, DES02F = DES02F + @Descuent, POR02F = POR02F + 0
END
END
FETCH NEXT FROM CliMes_Cursor2 INTO @Fechax, @CveGrupo, @CveClien,
@NomClien, @Importe, @CanSurti, @Descuent
END
CLOSE CliMes_Cursor2
DEALLOCATE CliMes_Cursor2
END


Y asi con todos los meses, agradeceria cualaquier ayuda.
Me disculpo si es escesivo el codigo que envio de ejemplo.
Espero que haber podido explicar mi problema.

Gracias y saludos.



Preguntas similares