Access: movernos por los registros través de un listbox
02/03/2022Diseño: crea tus propios botones de navegación
03/03/2022Es posible que trabajando con bases de datos SQL y Access, te hayas encontrado con el aviso “Conflicto de escritura” y no has sido capaz de resolverlo.
Este no es un tema nuevo. Si hacemos una simple búsqueda, observaremos que este problema está en la red desde hace muchos, mucho años. Aún así, es difícil encontrar soluciones reales al mismo. En este artículo vamos a analizar todas las posibles causas y soluciones, tanto las que personalmente ha sufrido como programador como con otras que he ido encontrando mientras intentaba resolver mi problema.
Causa 1 : varios usuarios intentan escribir a la vez en el mismo registro.
Si acudimos a la ayuda de Microsoft para entender este problema nos encontramos con la explicación más “simple y lógica” que se refiere a que dos usuarios, con sendos formularios, acceden a los datos concretos de un registro a la vez. El primer usuario establece un bloqueo que cuando el segundo usuario intenta hacer cambios, salta el mensaje de error.
La probabilidad de que esto ocurra en una pequeña organización, os la podéis imaginar. No obstante, debemos pensar que es posible, por lo que intentaremos solucionarlo tal y como nos indica la web de ayuda. Para ello disponemos de dos métodos:
- Establecer la propiedad RecordLocks del formulario en registro editado.
- Agregar “Docmd.RunCommand acCmdSaveRecord” al procedimiento “OnDeactivate” de ambos formularios para forzar a que guarde el registro cuando se desactive el formulario.
Si después de hacer todo esto no nos vuelve a aparecer el mensaje de error, ¡genial! Porque ya está solucionado y puedes dejar de leer este artículo.
El problema viene cuando sigue apareciendo el mensaje una y otra vez.
Me voy a enfocar en PostgreSQL que es la base de datos con la que trabajo, pero por lo que he podido ver durante este tiempo, otras bases de datos SQL también tienen este problema o parecido. Así, podrás utilizar esta información para guiarte en la solución del problema en estas bases de datos.
Causa 2: un recordset ha quedado abierto.
Si dejamos un recordset abierto, Access estará interpretando que alguien tiene bloqueado el recordset para su escritura, por lo que al intentar hacer cambios, nos mostrará el mensaje.
Para solucionarlo revisaremos nuestra programación para comprobar que en cualquier acceso a datos (ADO o DAO) no dejamos recordsets abiertos. Siempre que abrimos un recordset, debemos cerrarlo:
Set rst=CurrentDB.openrecordset(“MiTabla”)
…
rst.close
Set rst=nothing
Causa 3: ha quedado abierta otra instancia de Access
Tras un error, una instancia de Access ha quedado abierta y nosotros, al ejecutar nuestra aplicación, abrimos una segunda instancia sobre el mismo archivo.
Para comprobarlo, iremos al “Administrador de Tareas” y cerraremos las instancias que no estemos utilizando.
Causa 4: valores NULL y Cadena vacía
Access dispone de dos alternativas para indicar que no hay un registro en un campo: la cadena vacía y Null. Podemos escribir el valor de un campo como “”, por lo que Access interpretará que es una cadena de longitud 0, o podemos escribir “Null” y Access interpretará que el campo está vacío. PostgreSQL, por su parte, interpreta ambos casos como Null.
Para comprobar que no es la causa de nuestro problema o simplemente solucionarlo, deberemos comprobar que todas las cadenas vacías se almacenan como “Null”.
Causa 5: campo fecha y hora
El campo fecha y hora de PostgreSQL (timestamp) tiene una precisión de microsegundos, mientras que el campo fecha/hora de Access tiene una precisión de milisegundos, por lo que al hacer la comparación envía el mensaje de error que nos ha traído hasta aquí.
Si has utilizado la función Now() en Access para rellenar un campo fecha del tipo mencionado, es muy probable que te aparezca el error por la razón que antes hemos expuesto.
La solución pasa por utilizar campos de fecha y hora con una precisión menor, que iguale la precisión de Access. Podemos utilizar timestamp (3) para una precisión de milisegundos o timestamp (0) para una precisión de segundos. Deberemos fijarnos muy bien al diseñar nuestra base de datos y si nuestras fechas son normales, sin altas precisiones, lo mejor es trabajar con una precisión de segundos.
Si estamos construyendo una nueva base de datos nueva es sencillo seguir estas recomendaciones, pero ¿y si ya está creada y repleta de registros como seguramente es tu caso? Te indico unos sencillos pasos para que puedas solucionar el problema.
-- Creamos una columna temporal en nuestra tabla, con la precisión requerida. ALTER TABLE mitabla ADD COLUMN micampotemp timestamp(0) without time zone NULL; -- Copiamos los valores originales en el nuevo campo que hemos creado. UPDATE mitabla SET micampotemp = micampo::timestamp(0); -- Borramos el campo original, después de haber comprobado que los datos han sido copiados. ALTER TABLE mitabla DROP COLUMN micampo; -- Renombramos la nueva columna con el nombre original ALTER TABLE mitabla RENAME COLUMN micampotemp TO micampo;
Causa 6: campo Bit
La causa que presento a continuación, no se me ha presentado personalmente pero me ha parecido conveniente incluirla. Hace referencia a que hemos introducido un campo tipo Bit que no está inicializado, tenemos un campo bit en nuestra tabla y no tiene ningún valor, por lo que al vincularlo con Access, si la tabla no tiene ningún campo, al intentar introducir cualquier registro nos dará el error. Por el contrario, en una tabla que ya tenga datos, el error se mostrará tanto en INSERT como en UPDATE, ya que Access necesita mostrar un valor para ese campo y la base de datos no dispone de él, por lo que intenta escribir dos valores al mismo tiempo. (fuente Web4x4.es)
Para poder resolverlo deberemos asignar un valor predeterminado (0 o 1) al campo bit y por último volver a vincular la tabla o actualizar la vinculación.
Causa 7: campos calculados
En la misma fuente que el anterior encontramos otra posible situación con los campos real, decimal, etc… que dependen de fórmulas. Podemos encontrar el típico campo calculado importe (unidades x precio) y al intentar escribir en otro campo del registro nos muestra el error ya que el campo calculado es posterior al UPDATE y Access no sabe cuál es el correcto.
La solución pasa por crear un campo timestamp que incluya el momento de la actualización para que Access distinga entre ambos momentos y por último volver a vincular la tabla o actualizar la vinculación.
Como observarás, las causas pueden ser muy diversas, por lo que espero haberte sido de utilidad y si conoces algún caso distinto a los que enumero en este artículo, indícalo y lo incluiremos como problema/solución del mismo.
Créditos imagen: Pixabay
Actualización del 09/03/2022
Se me ha dado una nueva circustancia que quiero añadir al artículo y hace referencia a los formatos numéricos de nuestra base de datos y el tratamiento que hace Access de ellos.
En Access el campo tipo "number" puede dividirse en los siguientes tipos:
Byte: se usa para enteros comprendidos entre 0 y 255. El requisito de almacenamiento es 1 byte.
Entero: se usa para enteros comprendidos entre -32.768 y 32.767. El requisito de almacenamiento es 2 bytes.
Entero largo: se usa para enteros comprendidos entre -2.147.483.648 y 2.147.483.647. El requisito de almacenamiento es 4 bytes.
Single: se usa para valores numéricos de punto flotante que van de -3,4 x 1038 a 3,4 x 1038 y hasta siete dígitos significativos. El requisito de almacenamiento es 4 bytes.
Double: se usa para valores numéricos de punto flotante que van de -1,797 x 10308 a 1,797 x 10308 y hasta quince dígitos significativos. El requisito de almacenamiento es de 8 bytes.
Decimal: se usa para valores numéricos que van desde -9,999... x 1027 a 9,999... x 1027. El requisito de almacenamiento es de 12 bytes.
En las bases de datos SQL los datos numéricos difieren un poco de esta lista que hemos enumerado para Access. Si intentamos almacenar un dato numérico proveniente de una base de datos SQL, debemos de analizar la compatibilidad de ambos campos.
Si existe un error en los tipos, también se nos muestra el mensaje de error de "conflicto de escritura". Para resolverlo en PostgreSQL, deberemos seleccionar el tipo correcto de datos. Podemos utilizar el mismo sistema que para las fechas, como hemos comentado anteriormente.
4 Comments
Hay otra posibilidad de que salga un mensaje parecido a ese , aunque no es exactamente el mismo: Cuando estás escribiendo en un formulario (la propiedad Dirty es true) y modificas algo del mismo origen de datos mediante código. En ese caso, la solución es es escribir Me.Dirty = false o DoCmd.RunCommand AccmdSaveReveRecord antes de ejecutar el código que modifica la tabla.
Gracias Chea por tu comentario. SI te parece bien, ilustraremos tu ejemplo en un destello.
Hola Luis, gran artículo y como siempre super útil, me ha sido de gran ayuda.
Aunque me surge un problema con el tema del AccmdSaveReveRecord en el evento OnDeactivate. Siempre me tira el error 2501 “La acción RunCommand se canceló”. Incluso usando el Me.Dirty=False previo a este.
Por otra parte, me gustaría saver si hay algún Flag, propiedad o indicador, para saber si un registro está siendo bloqueado por otro usuario para interceptar el mensage y hacer aparecer una etiqueta o un indicador o un msgbox que le informe al usuario que el registro se encuentra bloqueado y en que equipo.
Le podrias dedicar un destello.
Muchas gracias
Por cierto, creo que está mal escrito,es DoCmd.RunCommand acCmdSaveRecord
no AccmdSaveReveRecord
Saludos