Comunidad Gambas-es
INSERT cannot ignore already existing row for this 'sqlite3' connection. - Versión para impresión

+- Comunidad Gambas-es (https://gambas-es.org)
+-- Foro: Gambas (https://gambas-es.org/forum-3.html)
+--- Foro: Bases de Datos (https://gambas-es.org/forum-6.html)
+--- Tema: INSERT cannot ignore already existing row for this 'sqlite3' connection. (/thread-1658.html)



INSERT cannot ignore already existing row for this 'sqlite3' connection. - nburgues - 05-04-2024

Hola Comunidad, estoy teniendo un problema con la actualización a Gambas 3.19. Tengo un programa de gestión y facturación que usa una base de datos Sqlite3. El programa esta funcionando desde hace 10 años. Al actualizar de Gambas 3.18 a Gambas 3.19 me sale un mensaje de error cada vez que quiero agregar un registro a la base. El mensaje es:

INSERT cannot ignore already existing row for this 'sqlite3' connection.

Esto sale al ejecutar la sentencia Create.

Código:
Private hcon As Connection
Private hresult As Result
hresult = hcon.Create("Clientes")

Este error no aparece en las versiones anteriores de Gambas y no he encontrado información acerca de este error.
Uso Ubuntu 18.04, pero lo probé en otras versiones y hace lo mismo.
Si uso:

[code]

el sistema funciona, pero tengo bases con 45 registros y me es imposible modificar todo.
Agradezco cualquier ayuda, muchas gracias!!


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - Shordi - 05-04-2024

Para responder a eso tienes que enviar la estructura de la tabla donde pretendes hacer el insert. El error indica que ya existe un registro con la clave primaria que se pretende insertar y eso es imposible de deducir del código que muestras. Pasa esa estructura y te podremos decir algo más.

Saludos


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - nburgues - 05-04-2024

Me lo hace con todas las tablas, siempre al ejecutar la sentencia CREATE me da el error y nunca me había pasado. Aca mando un ejemplo



Código:
Public Sub Button1_Click()
  Dim resultado As Result
  If Not Editar Then
     If hcon = Null Then
        Message.info("No hay conección con la base")
        Return
     Endif
  Endif
  If TextBox21.Text = "" Then
     Message.Info("Debe introducir un Código")
     Return ' Si no puse Código vuelvo
  Endif
  'ver si codigo existe
  If TextBox23.Text = "" Then
     Message.Info("Debe introducir un Costo")
     Return ' Si no puse Código vuelvo
  Endif
  If TextBox25.Text = "" Then
     Message.Info("La Utilidad no puede ser cero")
     Return ' Si no puse Código vuelvo
  Endif
  If TextBox26.Text = "" Then TextBox26.Text = "0"
  If TextBox27.Text = "" Then TextBox27.Text = "0"
  If TextBox28.Text = "" Then TextBox28.Text = "0"
  If Editar Then
     hresult["Codigo"] = TextBox21.text
     hresult["Detalle"] = TextBox22.text
     hresult["Costo"] = TextBox23.text
     hresult["Modificado"] = TextBox24.text
     hresult["Utilidad"] = TextBox25.text
     hresult["Stock"] = TextBox26.text
     hresult["MinimoStock"] = TextBox27.text
     hresult["CantidadPedido"] = TextBox28.text
     hresult["Prov1"] = TextBox31.text
     hresult["Codigo1"] = TextBox32.text
     hresult["prov2"] = TextBox33.text
     hresult["Codigo2"] = TextBox34.text
     hresult["prov3"] = TextBox35.text
     hresult["Codigo3"] = TextBox36.text
     hresult["prov4"] = TextBox37.text
     hresult["Codigo4"] = TextBox38.text
     hresult["prov5"] = TextBox39.text
     hresult["Codigo5"] = TextBox40.text
     hresult["Ubicacion"] = TextBox29.text
     hresult["Comentario"] = TextBox30.text
     Try hresult.Update()
     If Error Then
        Message.Info("Imposible Introducir esos datos")
     Endif
  Else
   resultado = hcon.Create("Lista")
   resultado["Codigo"] = TextBox21.Text
   resultado["Detalle"] = TextBox22.Text
   resultado["Costo"] = TextBox23.Text
   resultado["Modificado"] = TextBox24.Text
   resultado["Utilidad"] = TextBox25.Text
   resultado["Stock"] = TextBox26.Text
   resultado["MinimoStock"] = TextBox27.Text
   resultado["CantidadPedido"] = TextBox28.Text
   resultado["Prov1"] = TextBox31.Text   
   resultado["Codigo1"] = TextBox32.Text
   resultado["prov2"] = TextBox33.Text
   resultado["Codigo2"] = TextBox34.Text
   resultado["prov3"] = TextBox35.Text
   resultado["Codigo3"] = TextBox36.Text
   resultado["prov4"] = TextBox37.Text
   resultado["Codigo4"] = TextBox38.Text
   resultado["prov5"] = TextBox39.Text
   resultado["Codigo5"] = TextBox40.Text
   resultado["Ubicacion"] = TextBox29.Text
   resultado["Comentario"] = TextBox30.Text
   resultado.Update
   Try hcon.Exec("Select * From Lista")
   If Error Then
     Message.Info("Imposible Introducir esos datos")
   Endif
  Endif
  Me.Close
End

Cuando voy a la ayuda de CREATE me dice lo siguiente:

Return a read/write Result object used for creating records in the specified table.
Table: The name of the table.
Return: If set, the Result.Update() method will fill the Result with the contents of the newly inserted record. DESDE 3.19
IfNotExist: If set, the Result.Update() method will not raise an error if the record already exists (i.e. if a primary key or index constraints fails). DESDE 3.19

Evidentemente hubo cambios en la instrucción, pero no se como resolverlo.
Valoro mucho sus ayudas, Muchas gracias.


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - Shordi - 05-04-2024

Insisto: Pasa la estructura de las tablas, el error no lo está generando Gambas, lo está generando la BD. La puedes encontrar, por ejemplo, en la sección esquema del programa SqliteBrowser. Así:

[Imagen: 1kx1sx6.png]

Extrae la sentencia Create de una de las tablas que te dan error y súbela que la veamos.

Saludos.


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - nburgues - 06-04-2024

Esta es la sentencia CREATE desde el DB Browser:


Código:
CREATE TABLE 'Venta' ( 'NumeroVenta' INT4 NOT NULL , 'Fecha' DATETIME, 'NumeroCliente' INT4,
'Cliente' VARCHAR(40),'Cantidad1' INT4, 'CodigoProd1' VARCHAR(6), 'DetalleProd1' VARCHAR(40),
'PrecioProd1' FLOAT8, 'Cantidad2' INT4, 'CodigoProd2' VARCHAR(6),'DetalleProd2' VARCHAR(40),
'PrecioProd2' FLOAT8, 'Cantidad3' INT4, 'CodigoProd3' VARCHAR(6), 'DetalleProd3' VARCHAR(40),
'PrecioProd3' FLOAT8, 'Cantidad4' INT4, 'CodigoProd4' VARCHAR(6), 'DetalleProd4' VARCHAR(40),
'PrecioProd4' FLOAT8,'Cantidad5' INT4, 'CodigoProd5' VARCHAR(6), 'DetalleProd5' VARCHAR(40),
'PrecioProd5' FLOAT8, 'Cantidad6' INT4, 'CodigoProd6' VARCHAR(6),'DetalleProd6' VARCHAR(40),
'PrecioProd6' FLOAT8, 'Cantidad7' INT4, 'CodigoProd7' VARCHAR(6), 'DetalleProd7' VARCHAR(40),
'PrecioProd7' FLOAT8, 'Total' FLOAT8, 'Efectivo' FLOAT8, 'Tarjeta' FLOAT8, 'Cheque' FLOAT8,
'Debe' FLOAT8, 'Continua' BOOL,PRIMARY KEY (NumeroVenta) )



RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - Shordi - 06-04-2024

Bien un par de cositas con la salvedad de que los datos que dispongo son incompletos. Has subido el código de actualización sobre la tabla "Lista" pero has adjuntado la descripción de la tabla "Venta". Salvando esas distancias voy a suponer que en el código que maneje la tabla ventas utilizas la misma técnica que en la tabla Lista. En base a eso vemos que:
-No hay ningún campo que se refiera a la clave primaria de la tabla (numeroVenta). tampoco adjuntas el código con el que rellenas el formulario. Supongo que lo harás en base al NumeroVenta, que es la clave primaria. Algo así como:
hresult=hcon.edit("Venta","numeroVenta=&1",<Variable con el número de venta>)

Si lo haces a mano entonces te falta el campo que corresponda a NumeroVenta para que el usuario pueda teclearlo.

-No tienes ningún mecanismo para comprobar si el número que quieres grabar con el edit...update existe o no en la base de datos, por lo que es muy posible que te de fallo, más si no ves en la pantalla qué número estás intentando grabar.

-En el insertar ocurre lo mismo: No hay ningún mecanismo para asegurarse de que la tabla no disponga ya del  número que intentas grabar.

Manera de no tener problema con claves duplicadas. Utiliza las claves automáticas de SQLite o simplemente crea un campo que se llame id o rowid (SQLite lo considerará como un sinónimo de su clave automática) y lo declaras como integer PRIMARY KEY AUTOINCREMENT. Este campo se rellenará automáticamente al añadir el registro sin que tú tengas que ponerlo y te servirá como identificativo único para todas las líneas sin miedo a duplicados.

Luego un par de consejos sobre el código:

-No dejes el nombre de los campos por defecto (textbox1, textbox2, etc.) llámalos según lo que vayan a contener. Así la línea de código:
Código:
If TextBox21.Text = "" Then
    Message.Info("Debe introducir un Código")
    Return ' Si no puse Código vuelvo
  Endif
No dice nada de por qué es obligatorio ni de a qué código se refiere. Si el control textBox21 se llamase: tBCodigoProducto, la misma línea sería así:
Código:
If tbCodigoProducto.Text = "" Then
    Message.Info("Debe introducir un Código de Producto")
    Return ' Si no puse Código vuelvo
  Endif
Que es mucho más clara.
Además en las ristras de líneas como esta
Código:
s:
 hresult["NumeroVenta"] = TextBox20.text
      hresult["Codigo"] = TextBox21.text
      hresult["Detalle"] = TextBox22.text
      hresult["Costo"] = TextBox23.text
      hresult["Modificado"] = TextBox24.text
      hresult["Utilidad"] = TextBox25.text
      hresult["Stock"] = TextBox26.text
      hresult["MinimoStock"] = TextBox27.text
      hresult["CantidadPedido"] = TextBox28.text
      hresult["Prov1"] = TextBox31.text
      hresult["Codigo1"] = TextBox32.text
      hresult["prov2"] = TextBox33.text
      hresult["Codigo2"] = TextBox34.text
      hresult["prov3"] = TextBox35.text
      hresult["Codigo3"] = TextBox36.text
      hresult["prov4"] = TextBox37.text
      hresult["Codigo4"] = TextBox38.text
      hresult["prov5"] = TextBox39.text
      hresult["Codigo5"] = TextBox40.text
      hresult["Ubicacion"] = TextBox29.text
      hresult["Comentario"] = TextBox30.text
Imagina que confundes que textbox38 contiene en realidad lo que corresponde a textbox36 o viceversa.
¿Cómo detectar el error? Si ambos fuesen códigos numéricos, por ejemplo, la única manera sería repasar una a una las tablas de códigos hasta darte cuenta de que están cambiados... y eso puede ser una locura. Si pones a cada textbox su nombre significativo es muy fácil detectar el error y, mejor aún, casi imposible cometerlo ( hresul["Codigo1"]=tbCodigo2.text) es muy difícil de teclear sin que te cante el error.

Por último pero el más importante: Si quieres fiabilidad, sencillez y utilidad en tu programa, normaliza y organiza los datos en distintas tablas. Tal como has diseñado la tabla Venta, has colocado en ella al menos elementos de tres entidades distintas que no deberían estar juntas en la misma tabla:
    Las ventas(sinónimo de pedidos)
    El inventario
    los productos viéndote además, limitado a cinco productos por venta

Esto hace que esta tabla sea endiabladamente compleja de mantener sin errores. Por ejemplo si el código de un producto está en unos pedidos en codigo1, y en otros registros en código2 , etc y te ves obligado a cambiar el código... ¿qué haces? Si cuando llevas 1.000 ventas el proveedor le cambia el nombre al producto...¿qué haces?. Si necesitas recuentos y estadísticas de productos vendidos ¿qué haces?, etc. etc.

Solución: Divide en tablas relacionadas (que para eso SQLite es una base de datos relacional) y verás cómo todo te va mucho mejor.
En Internet hay toneladas de información sobre ello... y si no encuentras ni te aclaras, pregunta, que para eso estamos.

Saludos.


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - nburgues - 09-04-2024

Muchas gracias Shordi por tu explicación. Voy a tener en cuenta tus consejos. Lo que no entiendo porque con la versión 3.18 y las anteriores, el sistema anda bien. El comercio tiene 3 equipos con el mismo programa y la misma base de datos. En dos se actualizó a la versión 3.19 y dejo de funcionar y el tercero funciona correctamente con la 3.18. Los tres equipos están facturando desde hace diez años con el mismo programa. Eso me desconcierta.
De nuevo, muchas gracias por tus consejos y por dedicarle tiempo a mi problema, gracias!!!


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - Shordi - 10-04-2024

Cita:Lo que no entiendo porque con la versión 3.18 y las anteriores, el sistema anda bien
Las actualizaciones cambian cosas que no siempre vienen documentadas. Con SQLite en concreto puede ocurrir que en la última hayan aumentado la rigurosidad de los datos y activado cosas como el Pragma Foreign keys o el Pragma Automatic index o desactivado cosas como el Pragma Ignore Check Constraints o vaya usted a saber qué. De todas formas todo avance en la dirección del mantenimiento de la rigurosidad en las bases de datos es positivo. Si esos avances chocan con nuestros diseños... la culpa suele ser de los diseños. No te cuento lo que sufrí cuando se activó por primera vez la integridad referencial en Oracle porque es una película muy vieja... pero no creas que eres el primero al que le ha pasado algo así.

Saludos


RE: INSERT cannot ignore already existing row for this 'sqlite3' connection. - nburgues - 20-05-2024

Despues de mucho renegar, finalmente resolví el problema, lo cuento por si a alguien le sirve, actualicé Ubuntu de 18.04 a 20.04 y Gambas 3.19 corre perfectamente. Muchas gracias por sus ayudas!!