Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » SQL Server »

Problema con cursor

Estas en el tema de Problema con cursor en el foro de SQL Server en Foros del Web. Saludos que tal tengo un problema con un cursor que deberia actualizarme una columna que no es mas que un contador de registros por cliente ...
  #1 (permalink)  
Antiguo 20/04/2010, 10:07
 
Fecha de Ingreso: diciembre-2003
Mensajes: 595
Antigüedad: 20 años, 4 meses
Puntos: 1
Problema con cursor

Saludos que tal tengo un problema con un cursor que deberia actualizarme una columna que no es mas que un contador de registros por cliente
-------------------------------------------------------------------
declare @CONTADOR2 as int
declare @can_id as numeric(10)



DECLARE CUR1 cursor for
Select row_number() over(partition by CAN_ID order by fec_elab) as CONTADOR2, CAN_ID
from SEG_CANCER_NAB
where CAN_ID in (906930,905573)



OPEN CUR1

BEGIN TRAN

FETCH NEXT FROM CUR1
INTO @CONTADOR2,@can_id
WHILE @@FETCH_STATUS = 0

BEGIN

update SEG_CANCER_NAB
set Contador= @CONTADOR2
where Can_id=@can_id



FETCH NEXT FROM CUR1
INTO @CONTADOR2,@can_id



END
COMMIT TRAN


CLOSE CUR1
DEALLOCATE CUR1

-------------------------------------------------------------------


El resultado deberia ser algo asi

CONTADOR2 CAN_ID
1 905573
2 905573
1 906930
2 906930
3 906930

pero lo que hace es lo siguiente:

CONTADOR2 CAN_ID
2 905573
2 905573
3 906930
3 906930
3 906930

Como que me esta tomando solo el ultimo valor y lo esta actualizando alguien sabra porque se debe esto
  #2 (permalink)  
Antiguo 20/04/2010, 13:54
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 22 años, 4 meses
Puntos: 7
Respuesta: Problema con cursor

En general, en SQL Server 2005 o 2008 muy pocos problemas requieren del uso de un cursor. Este no es uno de ellos.

Código:
WITH upd AS (
    SELECT    ROW_NUMBER() OVER(PARTITION BY can_id order by fec_elab) as contador2,
            contador,
            can_id
    FROM    SEG_CANCER_NAB
    WHERE    CAN_ID in (906930,905573)
)
UPDATE upd
SET contador = contador2;
Cita:
alguien sabra porque se debe esto
Sucede que dentro del bucle del cursor al realizar el update, estás actualizando todos aquellos registros en los que can_id corresponde al @can_id en turno es decir...

Primera vez: @can_id = 905573, @CONTADOR2 = 1
Después del UPDATE:
1 905573
1 905573

Segunda vez: @can_id = 905573, @CONTADOR2 = 2
Después del UPDATE:
2 905573
2 905573

Como podrás ver, el cursor hace exactamente lo que esperararía: Actualizar n veces cada grupo.

Saludos.
  #3 (permalink)  
Antiguo 20/04/2010, 14:46
 
Fecha de Ingreso: diciembre-2003
Mensajes: 595
Antigüedad: 20 años, 4 meses
Puntos: 1
Respuesta: Problema con cursor

Cita:
Iniciado por Beakdan Ver Mensaje
En general, en SQL Server 2005 o 2008 muy pocos problemas requieren del uso de un cursor. Este no es uno de ellos.

Código:
WITH upd AS (
    SELECT    ROW_NUMBER() OVER(PARTITION BY can_id order by fec_elab) as contador2,
            contador,
            can_id
    FROM    SEG_CANCER_NAB
    WHERE    CAN_ID in (906930,905573)
)
UPDATE upd
SET contador = contador2;
Sucede que dentro del bucle del cursor al realizar el update, estás actualizando todos aquellos registros en los que can_id corresponde al @can_id en turno es decir...

Primera vez: @can_id = 905573, @CONTADOR2 = 1
Después del UPDATE:
1 905573
1 905573

Segunda vez: @can_id = 905573, @CONTADOR2 = 2
Después del UPDATE:
2 905573
2 905573

Como podrás ver, el cursor hace exactamente lo que esperararía: Actualizar n veces cada grupo.

Saludos.

Entiendo y mi problema es que no tengo un identificador unico para poder asociarlo uno a uno existira en sql server algo asi como un row_id para poder generar el update asociado a los grupos
  #4 (permalink)  
Antiguo 20/04/2010, 14:56
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 22 años, 4 meses
Puntos: 7
Respuesta: Problema con cursor

Para eso tienes ROW_NUMBER(). Usa el código que puse en la primera parte. Con eso solucionarás tu problema...
Es más, acabo de notar que puede ser aún más simple

Código:
WITH upd AS (
    SELECT    ROW_NUMBER() OVER(PARTITION BY can_id order by fec_elab) as contador2,
            contador
    FROM    SEG_CANCER_NAB
    WHERE    CAN_ID in (906930,905573)
)
UPDATE upd
SET contador = contador2;
Saludos.
  #5 (permalink)  
Antiguo 20/04/2010, 15:00
 
Fecha de Ingreso: diciembre-2003
Mensajes: 595
Antigüedad: 20 años, 4 meses
Puntos: 1
Respuesta: Problema con cursor

Cita:
Iniciado por Beakdan Ver Mensaje
Para eso tienes ROW_NUMBER(). Usa el código que puse en la primera parte. Con eso solucionarás tu problema.

Saludos.
Tienes toda la razon mas no entiendo te lo agradesco de corazon aunque no entiendo bien esa funcionalidad del with
  #6 (permalink)  
Antiguo 20/04/2010, 16:13
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 22 años, 4 meses
Puntos: 7
Respuesta: Problema con cursor

No es tan complicado. Usando tu consulta base
Código:
    SELECT    can_id,
            fec_elab
            contador,
            ROW_NUMBER() OVER(PARTITION BY can_id order by fec_elab) as contador2
    FROM    SEG_CANCER_NAB
    WHERE    CAN_ID in (906930,905573)
/*
  __Columnas en tabla___    Calculado
 /                      \ /          \
+------+--------+--------+------------+
|can_id|fec_elab|contador|ROW_NUMBER()|
+------+--------+--------+------------+
|906930|20100101|NULL    |1           |
+------+--------+--------+------------+
|906930|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100101|NULL    |1           |
+------+--------+--------+------------+
|905573|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100103|NULL    |3           |
+------+--------+--------+------------+
*/
Para cada fila tenemos un número de orden en cada grupo can_id. En teoría la operación de update sería tan simple como cambiar la consulta para actualizar la columna contador con el valor entregado por la función ROW_NUMBER:
Código:
UPDATE    SEG_CANCER_NAB
SET        contador = ROW_NUMBER() OVER(PARTITION BY ref.can_id ORDER BY ref.fec_elab)
FROM    SEG_CANCER_NAB AS ref
WHERE    ref.can_id in (906930,905573)
Pero la documentación indica que la función ROW_NUMBER sólo puede aparecer en las cláusulas SELECT y ORDER BY. Sin embargo ya tenemos todo lo que necesitamos, sólo se trata de actualizar una columna con el valor calculado. Así que es un caso ideal para usar una Common Table Expression (CTE). Para definir una, delimitamos la consulta con la cláusula WITH y le asignamos un nombre. La manera más fácil de comprenderla es si la imaginas como una vista definida temporalmente para la consulta. Al objeto definido se le pueden aplicar las mismas operaciones que a una vista (select, insert, delete, update). En resumen, la CTE mantendrá las referencias a los objetos originales con los cuales has definido la expresión (tablas, columnas, otras vistas). Por lo tanto podrás realizar todas las operaciones permitidas a los objetos base.

Saludos.
  #7 (permalink)  
Antiguo 20/04/2010, 16:22
 
Fecha de Ingreso: diciembre-2003
Mensajes: 595
Antigüedad: 20 años, 4 meses
Puntos: 1
Respuesta: Problema con cursor

Cita:
Iniciado por Beakdan Ver Mensaje
No es tan complicado. Usando tu consulta base
Código:
    SELECT    can_id,
            fec_elab
            contador,
            ROW_NUMBER() OVER(PARTITION BY can_id order by fec_elab) as contador2
    FROM    SEG_CANCER_NAB
    WHERE    CAN_ID in (906930,905573)
/*
  __Columnas en tabla___    Calculado
 /                      \ /          \
+------+--------+--------+------------+
|can_id|fec_elab|contador|ROW_NUMBER()|
+------+--------+--------+------------+
|906930|20100101|NULL    |1           |
+------+--------+--------+------------+
|906930|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100101|NULL    |1           |
+------+--------+--------+------------+
|905573|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100103|NULL    |3           |
+------+--------+--------+------------+
*/
Para cada fila tenemos un número de orden en cada grupo can_id. En teoría la operación de update sería tan simple como cambiar la consulta para actualizar la columna contador con el valor entregado por la función ROW_NUMBER:
Código:
UPDATE    SEG_CANCER_NAB
SET        contador = ROW_NUMBER() OVER(PARTITION BY ref.can_id ORDER BY ref.fec_elab)
FROM    SEG_CANCER_NAB AS ref
WHERE    ref.can_id in (906930,905573)
Pero la documentación indica que la función ROW_NUMBER sólo puede aparecer en las cláusulas SELECT y ORDER BY. Sin embargo ya tenemos todo lo que necesitamos, sólo se trata de actualizar una columna con el valor calculado. Así que es un caso ideal para usar una Common Table Expression (CTE). Para definir una, delimitamos la consulta con la cláusula WITH y le asignamos un nombre. La manera más fácil de comprenderla es si la imaginas como una vista definida temporalmente para la consulta. Al objeto definido se le pueden aplicar las mismas operaciones que a una vista (select, insert, delete, update). En resumen, la CTE mantendrá las referencias a los objetos originales con los cuales has definido la expresión (tablas, columnas, otras vistas). Por lo tanto podrás realizar todas las operaciones permitidas a los objetos base.

Saludos.



Gracias por la explicacion y una pregunta mas a esto que le llamas Common Table Expression pueden reemplazar como en este caso a los cursores
  #8 (permalink)  
Antiguo 20/04/2010, 16:40
Avatar de Beakdan  
Fecha de Ingreso: diciembre-2001
Ubicación: Monterrey, Nuevo León
Mensajes: 433
Antigüedad: 22 años, 4 meses
Puntos: 7
Respuesta: Problema con cursor

Para reemplazar a los cursores, debes emplear todas las herramientas que tengas a mano. Se supone que cuando realizamos operaciones en las bases de datos, estamos pensando en términos de conjuntos. Un cursor es llevar la mentalidad de programación estructurada a la base de datos.
No debes pensar en lo que harás en cada fila, sino lo que le harás a las columnas.
Por supuesto que una CTE será útil para reemplazar ciertos tipos de cursores pero no por si sólo. Por ejemplo, para realizar cálculos recursivos. Pero tienes a mano nuevas opciones, como son los operadores CROSS APPLY y OUTER APPLY. Tienes a mano también viejas técnicas como tablas de lookup y la famosa tabla de Números.
Mi recomendación, si el desarrollo eficiente de bases de datos te interesa es que consigas buen material de estudio. Por ejemplo, "SQL for Smarties" de Joe Celko, o "Inside SQL Server: TSQL Queryng" de Itzik Ben Gan.
Por cierto, a veces la única opción viable es un cursor. Pero cuando eso me ocurre, prefiero entregar los datos a procesar a la aplicación, e implementar allí la lógica que hubiera usado en el cursor.

Saludos.
  #9 (permalink)  
Antiguo 20/04/2010, 16:43
 
Fecha de Ingreso: diciembre-2003
Mensajes: 595
Antigüedad: 20 años, 4 meses
Puntos: 1
Respuesta: Problema con cursor

Cita:
Iniciado por Beakdan Ver Mensaje
Para reemplazar a los cursores, debes emplear todas las herramientas que tengas a mano. Se supone que cuando realizamos operaciones en las bases de datos, estamos pensando en términos de conjuntos. Un cursor es llevar la mentalidad de programación estructurada a la base de datos.
No debes pensar en lo que harás en cada fila, sino lo que le harás a las columnas.
Por supuesto que una CTE será útil para reemplazar ciertos tipos de cursores pero no por si sólo. Por ejemplo, para realizar cálculos recursivos. Pero tienes a mano nuevas opciones, como son los operadores CROSS APPLY y OUTER APPLY. Tienes a mano también viejas técnicas como tablas de lookup y la famosa tabla de Números.
Mi recomendación, si el desarrollo eficiente de bases de datos te interesa es que consigas buen material de estudio. Por ejemplo, "SQL for Smarties" de Joe Celko, o "Inside SQL Server: TSQL Queryng" de Itzik Ben Gan.
Por cierto, a veces la única opción viable es un cursor. Pero cuando eso me ocurre, prefiero entregar los datos a procesar a la aplicación, e implementar allí la lógica que hubiera usado en el cursor.

Saludos.
Muy bien voy a conseguir el material que mencionas y nuevamente muchas gracias.
  #10 (permalink)  
Antiguo 22/04/2010, 01:25
 
Fecha de Ingreso: febrero-2005
Mensajes: 27
Antigüedad: 19 años, 2 meses
Puntos: 1
Pregunta Respuesta: Problema con cursor

yo tengo un problema semejante solo que yo necesito un resultado diferente, es decir yo solo necesito los valores mas altos (tengo una tabla con dos columnas "NOMBRE" y "EDAD", necesito saber cuantas veces se repite la misma edad, no importa el nombre), tomando el ejemplo anterior mi resultado seria:

Código:
/*
  __Columnas en tabla___    Calculado
 /                      \ /          \
+------+--------+--------+------------+
|can_id|fec_elab|contador|ROW_NUMBER()|
+------+--------+--------+------------+
|906930|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100103|NULL    |3           |
+------+--------+--------+------------+

*/

espero haberme explicado, gracias!!
  #11 (permalink)  
Antiguo 22/04/2010, 16:29
 
Fecha de Ingreso: febrero-2005
Mensajes: 27
Antigüedad: 19 años, 2 meses
Puntos: 1
De acuerdo Respuesta: Problema con cursor

Cita:
Iniciado por roach6891 Ver Mensaje
yo tengo un problema semejante solo que yo necesito un resultado diferente, es decir yo solo necesito los valores mas altos (tengo una tabla con dos columnas "NOMBRE" y "EDAD", necesito saber cuantas veces se repite la misma edad, no importa el nombre), tomando el ejemplo anterior mi resultado seria:

Código:
/*
  __Columnas en tabla___    Calculado
 /                      \ /          \
+------+--------+--------+------------+
|can_id|fec_elab|contador|ROW_NUMBER()|
+------+--------+--------+------------+
|906930|20100102|NULL    |2           |
+------+--------+--------+------------+
|905573|20100103|NULL    |3           |
+------+--------+--------+------------+

*/

espero haberme explicado, gracias!!
PERDOOOON!! anoche estaba algo dormido y ya ni podia pensar! pero aqui tengo la solucion a mi pregunta:

select edad, count(edad) cantidad from test group by edad

tomando el ejemplo anterior

select can_id, count(can_id) cantidad from tabla group by can_id

gracias de todos modos y disculpen las molestias xD
  #12 (permalink)  
Antiguo 04/10/2010, 11:45
 
Fecha de Ingreso: octubre-2010
Mensajes: 12
Antigüedad: 13 años, 6 meses
Puntos: 0
Respuesta: Problema con cursor

HOLA CHICOS YO TENGO UN GRAN PROBLEMA NO SE COMO SACAR EN SQL CIERTO NUMERO DE REGISTROS DE UN REGISTRO QUE TIENE n COINCIDENCIAS EJEMPLO
SI UNA LLAVE
ADER TIENE 1000 000 DE COINCIDENCIAS Y
AAAA TIENE 50000 COINCIDENCIAS Y ASI DIFERENTES CVES YO QUIERO SACAR SOLO 100 DE CADA UNO COMO HAGO UN TOP NO SIRVE PORQUE EM DA TOP DE LA TABLA SI EL PONGO EL TOP 100 ME DA LOS 100 PRIMEROS D ELA TABLA Y YO QUIERO 100 DE CADA CLAVE O REGISTRO

GRACIAS
  #13 (permalink)  
Antiguo 04/10/2010, 18:14
 
Fecha de Ingreso: febrero-2005
Mensajes: 27
Antigüedad: 19 años, 2 meses
Puntos: 1
Respuesta: Problema con cursor

a chis no te entendi mmm pero a ver si es asi:

la unica que se me ocurre es con un store

Código:
create proc spuCOMOSEA
as
begin
select top 100 * from NOMBRE_TABLA where NOMBRE_CAMPO = 'ADER'
union all
select top 100 * from NOMBRE_TABLA where NOMBRE_CAMPO = 'AAAA'
end
puedes hacerlo con una view tmb ya si quieres hacer variable el campo pues ponle tus variables antes del as y listo

p.d. espero que no sea tu tarea

Etiquetas: cursor
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 2 personas




La zona horaria es GMT -6. Ahora son las 18:20.