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

Error de "duplicate key" en inserción cuando no existe tal violación sql

Estas en el tema de Error de "duplicate key" en inserción cuando no existe tal violación sql en el foro de Mysql en Foros del Web. [CODE][HIGHLIGHT="MySQL"]HOla a todos tengo un sp en donde hago una serie de consultas, operaciones, update e insert a varias tablas a la vez, el asunto ...
  #1 (permalink)  
Antiguo 11/09/2012, 23:12
 
Fecha de Ingreso: enero-2012
Mensajes: 23
Antigüedad: 12 años, 3 meses
Puntos: 0
Error de "duplicate key" en inserción cuando no existe tal violación sql

[CODE][HIGHLIGHT="MySQL"]HOla a todos tengo un sp en donde hago una serie de consultas, operaciones, update e insert a varias tablas a la vez, el asunto es el siguiente que en el siguiente sp que les mostraré tenía un problema incialmente de un error 1329 cuando le agregue la cláusula para corregirlo del "handler 1329" me dejo solucionó lo del fetch vacío pero ahora me salió el problema del error 1452 que dice que no puedo ni agregar ni actualizar una fila hija, cosa que no es cierta porque siempre lo termina haciendo en la tabla respectiva "control_situalab"
Lo que no comprendo porque me da ese error de violación de llave ya que el error literalmente que me tira es este:
------------------------------------------------------------------------------------------------------
Query: CALL aplicar_incapacidad_medica(@fec1,@fec2,2,31,@aplic a)

Error Code: 1452
Cannot add or update a child row: a foreign key constraint fails (`saerp`.`control_situalab`, CONSTRAINT `FK_controlSituaLab_empleados` FOREIGN KEY (`idempleado`) REFERENCES `empleados` (`idempleado`))
----------------------------------------------------------------------------------------------------
Me dice eso pero al revisar la tabla si hizo el insert que lleva el sp.

El codigo de mi sp es este:

Código MySQL:
Ver original
  1. DECLARE CONTINUE HANDLER FOR 1329 SET no_hay_accpers=1;
  2.    
  3.     #Obtenemos porcentaje de incapacidad y dias maximos de incapacidad con responsabilidad patronal
  4.     SELECT porc_pago_incap, dias_max_pago_incap, modalidad_planilla
  5.     INTO porc_tblconfig, dias_tblconfig, modpln_tblconfig
  6.     FROM empresas INNER JOIN configuraciones USING(codconfig) WHERE codempresa=1;      
  7.    
  8.     #Obtenemos planilla de sueldos activa
  9.     SET plnsuel = (SELECT plnsueldo);
  10.    
  11.     #Abrimos Result set
  12.     OPEN rg_accpers;
  13.    
  14.     #Leemos e iteramos la colección abierta
  15.     leer_bucle:LOOP
  16.         #Revisamos si hay filas que recorrer, sino lo hay salimos del bucle
  17.         IF no_hay_accpers = 1 THEN
  18.             #Da el pase para salir del flujo del Result Set una vez finalizada sus iteraciones o simplemente el cursor venia vacío
  19.             LEAVE leer_bucle;
  20.         END IF;
  21.         #Este IF funciona con LOOP ... END ó REPEAT ... END REPEAT
  22.        
  23.     #Controlamos el recorrido del flujo para ver si nos salimos
  24.     IF no_hay_accpers = 0 THEN
  25.  
  26.         #Extraemos valores del Result set
  27.         FETCH rg_accpers INTO idemp, porc, dura, pago_incap_maxdias, codsolic, rgcont, fecha_in, fecha_fn, dura_cub;       
  28.          
  29.         #Este módulo de cálculos solo aplica para planillas mensuales
  30.         IF (DAY((SELECT fecha2)) > 27) THEN
  31.        
  32.             #Modalidad de pago de la planilla
  33.             CASE modpln_tblconfig
  34.                 WHEN 'S' THEN #Modalidad semanal
  35.                     SET factor_sueldo = 4;             
  36.                 WHEN 'Q' THEN #Modalidad quincenal
  37.                     SET factor_sueldo = 2;
  38.                 ELSE #Modalidad mensual
  39.                     SET factor_sueldo = 1;
  40.             END CASE;
  41.             #Màximo de dias a pagar por incapacidad. Incapacidades solo se pagaran en el corte de planilla de fin de mes
  42.             SET vp_dias_maxpag = 30;
  43.             #Sueldo siempre se dividirá entre 30 días no importando la modalidad de la planilla    
  44.             IF (SELECT dias_laborables)<28 THEN
  45.                 SET dias_lab = 30;
  46.             ELSE
  47.                 SET dias_lab = 30;         
  48.             END IF;
  49.            
  50.             #Ningun dia de incapacidad pagado
  51.             SET dura_real = dura;
  52.             SET dura_cub_real = dura_cub;  
  53.             #Se decide si la empresa pagará la incapacidad
  54.             IF dura_cub_real = 0 AND !vp_calcIncap THEN        
  55.                 IF dura_real > dias_tblconfig THEN  #Incapacidad 25%
  56.                     IF porc > 0 THEN #La empresa le pagará la incapacidad
  57.                         IF dura_real > vp_dias_maxpag THEN
  58.                             SET vp_dias_res = dura - vp_dias_maxpag;
  59.                             SET vp_dias_pag = dura - vp_dias_res;
  60.                             SET dura = vp_dias_pag; #Dias a pagar en planilla
  61.                             SET dura_cub = vp_dias_pag; #Dias cubiertos del total de dias de incapacidad   
  62.                             SET vp_calcIncap = TRUE;
  63.                         ELSE                           
  64.                             SET dura = dura;
  65.                             SET dura_cub = dura;   
  66.                             SET vp_calcIncap = TRUE;
  67.                         END IF;
  68.                     ELSE #La empresa no le pagará la incapacidad
  69.                         SET vp_calcIncap = FALSE;              
  70.                     END IF;                
  71.                 ELSE #Incapacidad 3 dias max
  72.                     IF pago_incap_maxdias THEN #La empresa le pagara la incapacidad
  73.                         IF dura_real > vp_dias_maxpag THEN
  74.                             SET vp_dias_res = dura - vp_dias_maxpag;
  75.                             SET vp_dias_pag = dura - vp_dias_res;
  76.                             SET dura = vp_dias_pag; #Dias a pagar en planilla
  77.                             SET dura_cub = vp_dias_pag; #Dias cubiertos del total de dias de incapacidad   
  78.                             SET vp_calcIncap = TRUE;
  79.                         ELSE                           
  80.                             SET dura = dura;
  81.                             SET dura_cub = dura;   
  82.                             SET vp_calcIncap = TRUE;
  83.                         END IF;
  84.                     ELSE #La empresa no le pagara la incapacidad
  85.                         SET vp_calcIncap = FALSE;
  86.                     END IF;                    
  87.                 END IF;
  88.                 SET ctrl_situalab = TRUE;
  89.             END IF;
  90.        
  91.             #No se han pagado todos los dias de incapacidad, hay pendientes
  92.             IF dura_cub_real > 0 AND dura_real != dura_cub_real AND !vp_calcIncap THEN         
  93.                 SET vp_dias_res = dura - dura_cub;
  94.                 IF vp_dias_res > vp_dias_maxpag THEN
  95.                     SET vp_dias_res = dura - vp_dias_maxpag;
  96.                     SET vp_dias_pag = dura - vp_dias_res;
  97.                     SET dura = vp_dias_pag; #Dias a pagar en planilla
  98.                     SET dura_cub = vp_dias_pag; #Dias cubiertos del total de dias de incapacidad
  99.                     SET vp_calcIncap = TRUE;
  100.                 ELSE                   
  101.                     SET dura = vp_dias_res;
  102.                     SET dura_cub = vp_dias_res;
  103.                     SET vp_calcIncap = TRUE;
  104.                 END IF;
  105.                 SET ctrl_situalab = TRUE;
  106.             END IF;
  107.            
  108.             #Obtenemos cálculos respectivos a la incapacidad
  109.             IF vp_calcIncap THEN
  110.                 IF dura_real > dias_tblconfig THEN #Incapacidad de 25%
  111.                     IF porc > 0 THEN #Empresa decidió pagar el 25% correspondiente a los dias de incapacidad
  112.                         SET sueldo = (SELECT sueldo_base+sueldo_vari AS suel FROM empleados WHERE idempleado=idemp);
  113.                         SET monto_incap = dura * ( (sueldo * factor_sueldo) / dias_lab);
  114.                         SET pago_incap = monto_incap * (porc / 100);
  115.                     ELSE #Empresa decidió no pagarlos
  116.                         SET pago_incap = 0;            
  117.                     END IF;        
  118.                 ELSE #Incapacidad de 3 dias max        
  119.                     IF pago_incap_maxdias THEN #Pagará inncapacidad
  120.                         SET sueldo = (SELECT sueldo_base + sueldo_vari AS sue FROM empleados WHERE idempleado=idemp);
  121.                         SET monto_incap = dura * ( (sueldo * factor_sueldo) / dias_lab);
  122.                         SET pago_incap = monto_incap;
  123.                     ELSE #No pagará incapacidad
  124.                         SET pago_incap = 0;
  125.                     END IF;
  126.                 END IF;
  127.                
  128.                 #Actualizamos el detalle de la planilla en tabla deta_planilla_docus
  129.                 IF pago_incap > 0 THEN         
  130.                     INSERT INTO deta_planilla_docus (codplnsuel, codaccpers, idempleado, tipo_doc) VALUES (plnsuel, codsolic, idemp, 'PLNSUEL');
  131.                     SET id_deta_pln_docus = (SELECT numero FROM deta_planilla_docus ORDER BY numero DESC LIMIT 1);                         
  132.                     #Obtenemos algunos datos
  133.                     SET incmed_dias_detaplnsuel = (SELECT duracion FROM deta_planilla_docus WHERE numero = id_deta_pln_docus AND codplnsuel = plnsuel AND codaccpers = codsolic AND idempleado = idemp);
  134.                     SET incmed_monto_detaplnsuel = (SELECT monto FROM deta_planilla_docus WHERE numero = id_deta_pln_docus AND codplnsuel = plnsuel AND codaccpers = codsolic AND idempleado = idemp);
  135.                     #Actualizamos los dias incapacitados en tabla deta_plnsueldos. Si aplica       
  136.                     UPDATE deta_planilla_docus SET                 
  137.                         duracion = IF(dura > 0, incmed_dias_detaplnsuel + dura_cub, 0),
  138.                         monto = IF(pago_incap > 0, incmed_monto_detaplnsuel + pago_incap, 0)
  139.                         WHERE numero = id_deta_pln_docus AND codplnsuel = plnsuel AND codaccpers = codsolic AND idempleado = idemp;
  140.                 END IF;            
  141.    
  142.                 #Actualizamos los dias incapacitados cubiertos en tabla accpers_deta. Si aplica
  143.                 UPDATE accpers_deta SET
  144.                     duracion_cub = dura_cub_real + dura_cub
  145.                     WHERE idempleado = idemp AND codaccpers = codsolic;                        
  146.             END IF;
  147.            
  148.             #Hacemos bitácora de la situación laboral del empleado
  149.             IF ctrl_situalab THEN
  150.                 INSERT INTO control_situalab (idempleado, fecha1, fecha2, codsitualab, codplnsuel, tipodoc)
  151.                     VALUES (idemp, fecha_in, fecha_fn, 3, plnsuel, 'PLNSUEL');                 
  152.             END IF;
  153.                        
  154.             #Dias de incapacidad pagados en su totalidad o simplemente accpers aplicada porque empresa no quiso pagar incapacidad
  155.             IF (dura_real = (dura_cub_real + dura_cub) && pago_incap>0) THEN
  156.                 SET vp_okAccpers = TRUE;                 
  157.             ELSEIF (!pago_incap_maxdias && pago_incap=0) THEN
  158.                 SET vp_okAccpers = TRUE;
  159.             ELSEIF (porc > 0 && pago_incap=0) THEN
  160.                 SET vp_okAccpers = TRUE;
  161.             END IF;
  162.        
  163.             IF vp_okAccpers THEN
  164.                 UPDATE accpers SET aplicada = 1 WHERE codaccpers = codsolic;
  165.             END IF;            
  166.         END IF;
  167.                
  168.  
  169.        
  170.             #Contamos las iteraciones
  171.             SET contador = contador + 1;
  172.             #Tamaño del Result set coincide con las iteraciones hechas
  173.                
  174.             #Si el Result set filtrado es igual a la cantidad de UPDATE hechas
  175.             SET aplicada = contador; #1; #Indicar al usuario que se efectuo la operación correctamente
  176.             #SET @aplicada_INCMED = 1;
  177.     END IF;    
  178.        
  179.     END LOOP leer_bucle;
  180.    
  181.     #Cerramos la colección Result set
  182.     CLOSE rg_accpers;
  183.    
  184.     #Inicializamos el controlador utilizado
  185.     SET no_hay_accpers = 0;
  186.    
  187.     #No encontró registros
  188.     IF contador = 0 THEN
  189.         #Indicar al usuario que no se llevo a cabo la operacion porque no arrojo nada la consulta
  190.         SET aplicada = 0; #Parametro de salida para SP local       
  191.     END IF;
  #2 (permalink)  
Antiguo 11/09/2012, 23:14
 
Fecha de Ingreso: enero-2012
Mensajes: 23
Antigüedad: 12 años, 3 meses
Puntos: 0
Respuesta: Error de "duplicate key" en inserción cuando no existe tal violación sql

La linea del insert que me duplicacion segun el error es la 149
  #3 (permalink)  
Antiguo 12/09/2012, 04:17
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 5 meses
Puntos: 2658
Respuesta: Error de "duplicate key" en inserción cuando no existe tal violación sql

Código MySQL:
Ver original
  1. IF ctrl_situalab THEN
  2.     INSERT INTO control_situalab (idempleado, fecha1, fecha2, codsitualab, codplnsuel, tipodoc)
  3.     VALUES (idemp, fecha_in, fecha_fn, 3, plnsuel, 'PLNSUEL');                
Efectivamente, es la única parte donde se puede producir.
Hay tres esscenarios poribles:
1) Si la variable idemp es NULL o contiene un valor que no exista en la tabla "empleados".
En otras palabras, un problema de datos. La única solución es verificar manualmente los datos de la tabla que origina ese valor, respecto de la tabla referida (empleados), para corroborar que no haya un dato ilegal en alguna parte.
Hazlo: revisalo.
No tienes idea de la cantidad de veces que nos han asegurado que estaba todo bien, y luego resultó que en realidad había un dato mal guardado de origen...

2) Si el campo idempleado es PK de esa tabla. Siendo PK es único, y si esa tabla se usa para contener información de diferentes momentos de un mismo empleado, hay un error de definición de tabla. La PK en ese caso debe ser de al menos dos campos.

3) El campo en cuestión es UNIQUE, cosa parecida a que sea PK. Tiene en esencia las mismas restricciones.

Por cierto: Hay algunos defectos formales no funcionales en algunas partes del SP (códigos superfluos o innecesarios).
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Última edición por gnzsoloyo; 12/09/2012 a las 06:47
  #4 (permalink)  
Antiguo 12/09/2012, 19:30
 
Fecha de Ingreso: enero-2012
Mensajes: 23
Antigüedad: 12 años, 3 meses
Puntos: 0
Respuesta: Error de "duplicate key" en inserción cuando no existe tal violación sql

Cita:
Iniciado por gnzsoloyo Ver Mensaje
Código MySQL:
Ver original
  1. IF ctrl_situalab THEN
  2.     INSERT INTO control_situalab (idempleado, fecha1, fecha2, codsitualab, codplnsuel, tipodoc)
  3.     VALUES (idemp, fecha_in, fecha_fn, 3, plnsuel, 'PLNSUEL');                
Efectivamente, es la única parte donde se puede producir.
Hay tres esscenarios poribles:
1) Si la variable idemp es NULL o contiene un valor que no exista en la tabla "empleados".
En otras palabras, un problema de datos. La única solución es verificar manualmente los datos de la tabla que origina ese valor, respecto de la tabla referida (empleados), para corroborar que no haya un dato ilegal en alguna parte.
Hazlo: revisalo.
No tienes idea de la cantidad de veces que nos han asegurado que estaba todo bien, y luego resultó que en realidad había un dato mal guardado de origen...

2) Si el campo idempleado es PK de esa tabla. Siendo PK es único, y si esa tabla se usa para contener información de diferentes momentos de un mismo empleado, hay un error de definición de tabla. La PK en ese caso debe ser de al menos dos campos.

3) El campo en cuestión es UNIQUE, cosa parecida a que sea PK. Tiene en esencia las mismas restricciones.

Por cierto: Hay algunos defectos formales no funcionales en algunas partes del SP (códigos superfluos o innecesarios).
HOla gnzsoloyo! primeramente agradezco el tiempo tomado para revisar mi código y responder a mi problema!
Fijate que manualmente he revisado el insert y funciona pero me entra la duda y es q como dices en el punto 1 que la variables idemp es NULL pero supuestamente le he puesto el handler 1329 para evitar que siga el bucle en caso ya no haya mas registros en el fetch pero pareciera que como que siempre intenta recorrerlo y he puesto un IF en donde si es TRUE o FALSE siempre haga verdadera la variable
"ctrl_situalab" entonces siempre entraria en ese IF donde esta el insert, ahora cuando quito el handler 1329 si funciona el insert y no da problema. Ahora bien anoche hice otras pruebas y es que puse un IF donde pregunto si es uno la variable "no_hay_accpers" y si es asi el respectivo LEAVE, pero ahora puse otro IF donde pregunto si la variable "no_hay_accpers" es cero que haga todo lo que debe hacer cuando el fetch trae registro, todo eso dentro del IF y ahi si no me da problema pero veo que siempre me sale el problema del fetch vacío osea no me funciona el handler 1329, espero me haya dado a entender y sino con gusto te replanteo lo que he intentado esplicarte o si quieres que te de el script completo tu me diras???? Gracias nuevamente de antemano por tu buena intención

Etiquetas: mysql-error, procedure, store
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




La zona horaria es GMT -6. Ahora son las 04:01.