https://foro.gambas-es.org/viewtopic.php?f=3&t=5761
-----------------------------------
tincho
Martes, 06 Septiembre 2016, 23:00

Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas [Solucionado]
-----------------------------------
Hola seguramente esto esta explicado en alguna parte de este foro, pero no logre encontrarlo.

Hice una base de datos de música en sqlite3 que se encuentra relacionada mediante indices, y ahora intento insertar un registro en una vista, de tal manera que le diga los valores de los campos en forma de "texto" y que la base se busque la vida para insertar un "entero" que es el indice de ese texto en otra tabla.
La teoría todo fenómeno, pero no funciona.

Alguien podría decirme que estoy haciendo mal o que me falta configurar, y aun mejor como es la sentencia de insercion SQL.

Adjunto la base y un diagrama de como esta relacionada.

sentencia sql de la vista

[code linenumbers=false syntax=sql]
select
trackindx,
tracktitle,
tracknum,
albumname as trackalbum,
artistname as trackartist,
genrename as trackgenre,
trackyear,
typename as tracktype

from track

left join  album on trackalbum=albumindx
left join  artist on trackartist=artistindx
left join  genre on trackgenre=genreindx
left join  type on tracktype=typeindx
[/code]

Saludos y gracias.


-----------------------------------
shordi
Miercoles, 07 Septiembre 2016, 08:27

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
[quote] como es la sentencia de insercion SQL.[/quote]

Tal sentencia no existe. Una vista es lo que su nombre indica: Una Vista. Una forma de ver los registros "esparcidos" en varias tablas y/o formateados de manera más "visual".

Una vista no se actualiza. Sólo se "ve".

Tienes que insertar/modificar/eliminar los registros en sus tablas correspondientes.

Saludos.


-----------------------------------
tincho
Miercoles, 07 Septiembre 2016, 10:31

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
ok, vale voy a hacer la pregunta de otra manera.

En el ejemplo hay una tabla principal llamada tracks (canciones) donde hay campos como artista o álbum, pero estos son campos que están relacionados mediante una clave foránea con otras tablas.
¿Como puedo insertar registros en tracks y si por ejemplo no existe un álbum que sqlite cree ese álbum en la tabla albums y en la tabla tracks se ponga ese indice nuevo correspondiente?

Saludos.


-----------------------------------
chaskux
Miercoles, 07 Septiembre 2016, 14:48

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
estimado tincho.

lo que dice shordi es correcto, una vista es solo una capa de una serie de tablas reales.. por lo que si lo que deseas es que te "aparezca" un registro nuevo en la vista "track" debes crear el set de registros en todas las tablas que mencionas en tu query, de lo contrario podrás esperar sentado tomando un rico café para que esto ocurra por arte de magia. Ahí te toca trabajar en los insert de cada uno de ellos.


-----------------------------------
shordi
Miercoles, 07 Septiembre 2016, 18:12

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
[quote]¿Como puedo insertar registros en tracks y si por ejemplo no existe un álbum que sqlite cree ese álbum en la tabla albums y en la tabla tracks se ponga ese indice nuevo correspondiente?[/quote]
Con un proceso de gambas. SQLite no puede hacer eso por tí. La integridad referencial se ocupa de que todas las referencias que existan en la base de datos sean correctas. Es decir, que si tú pones que esto es de tal album, tal album exista. Pero no puede crear las referencias. Tú, en tu proceso de gambas, eres quien primero ha de comprobar si el álbum existe, crearlo si no es así y luego añadir las pistas.
Hay varias formas de hacerlo. 

Una es:

1.- Almacenar en un combobox todos los álbumes del artista (o todos a lo bestia, como desees)
2.- Si el album existe lo seleccionas y punto
3.- Si no existe lo tecleas y entonces, en el evento lostfocus, por ejemplo, del combobox  compruebas si lo tecleado está en la lista y si no, lo añades a la tabla
4.- Cuando llega el momento de grabar la pista ya tienes el álbum disponible.

Inconveniente: si tecleas el álbum pero no grabas la pista tienes un álbum vacío...(cosa que puede ser buena o mala, según depende)

Otra es dejar toda la tarea al proceso de grabar, que 

1.- Comprueba si la propiedad .text del combobox es un elemento de la lista y si no lo es 
2.- Crea el álbum y
3.- Graba la pista

Inconveniente... no se me ocurre ninguno importante salvo unos milisengundos usados en comprobaciones...

Saludos


-----------------------------------
jsbsan
Miercoles, 07 Septiembre 2016, 20:14

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
tincho:

[quote]en la tabla tracks se ponga ese indice nuevo correspondiente?[/quote]
Añadiendo lo que te comenta Shordi, para saber los datos del último registro introducido (por ejemplo su indice), hay varias formas de obtenerlo:

select * from tabla order by id DESC limit 1

(obtenemos un result con todos los campos del registro último introdudido)

o

SELECT MAX(id) FROM tabla

(obtenemos un result, con el numero mayor de id)


Nota:
siempre que el campo "id" sea autoincremental

Fuente:
http://www.forosdelweb.com/f18/obtener-ultimo-registro-mysql-671592/


-----------------------------------
tincho
Jueves, 08 Septiembre 2016, 21:38

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
[quote user="shordi" post="34260"]Con un proceso de gambas. SQLite no puede hacer eso por tí. La integridad referencial se ocupa de que todas las referencias que existan en la base de datos sean correctas. Es decir, que si tú pones que esto es de tal album, tal album exista. Pero no puede crear las referencias. Tú, en tu proceso de gambas, eres quien primero ha de comprobar si el álbum existe, crearlo si no es así y luego añadir las pistas.
Hay varias formas de hacerlo.[/quote]
Si, exacto por ahí van los tiros, pero lo que estoy queriendo hacer es un programa que pueda "alimentar" una base de datos a medida que le son pasados archivos con meta datos, por ejemplo .ogg.
Lo que hacen todos los programas de colecciones de música, digamos.
Pero creo que ya tengo los conceptos asimilados  :roll: asi que ye les contare como fue la cosa en unos...¿dias?
Gracias por la ayuda.
Saludos.


-----------------------------------
tincho
Jueves, 08 Septiembre 2016, 21:41

Re: Insertar Un Registro En Sqlite En Una Vista
-----------------------------------
[quote user="jsbsan" post="34269"]select * from tabla order by id DESC limit 1
(obtenemos un result con todos los campos del registro último introdudido)
o
SELECT MAX(id) FROM tabla
(obtenemos un result, con el numero mayor de id)
siempre que el campo "id" sea autoincremental
[/quote]
Gracias, creo que este tipo de sentencias SQL sera útil para agregar registros en las tablas accesorias y principal.
Saludos.


-----------------------------------
shordi
Viernes, 09 Septiembre 2016, 05:11

Re: Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas
-----------------------------------
[quote]Si, exacto por ahí van los tiros, pero lo que estoy queriendo hacer es un programa que pueda "alimentar" una base de datos a medida que le son pasados archivos con meta datos, por ejemplo .ogg.
Lo que hacen todos los programas de colecciones de música, digamos.[/quote]
Buff... olvídate entonces de la integridad referencial. Si tu fuente de datos son archivos creados por otras personas con sus propios criterios y maneras de teclear los datos, es imposible que cuadres y sistematices todo de manera perfecta. 
Alguien puede catalogar que "Money" pertenece a "The Dark Side of the Moon" y alguien puede catalogar que pertenece a "Dark Side of the Moon, The" 
Imposible predecir todo eso, imposible establecer las referencias de manera coherente.

Ahí, me temo, te toca "tragar" todo lo que los archivos de metadatos te cuenten y luego, a lo sumo, establecer en tu programa procedimientos para "corregir" los datos. Algo así como "Cambiar todas las pistas que pertenezcan al álbum tal por el álbum cual" y "Borrar álbumes sin pistas", etc. etc.

Saludos


-----------------------------------
tincho
Viernes, 09 Septiembre 2016, 15:19

Re: Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas
-----------------------------------
[quote user="shordi" post="34298"]...todo lo que los archivos de meta datos te cuenten y luego, a lo sumo, establecer en tu programa procedimientos para "corregir" los datos. Algo así como "Cambiar todas las pistas que pertenezcan al álbum tal por el álbum cual" y "Borrar álbumes sin pistas", etc. etc.[/quote]
Si pensaba hacer algo así para cargar todo, pero cuando algo no cuadre en el momento de la carga here un formulario que muestre el disco y junto a cada dato que no cuadre algunas sugerencias para elegir, y tener una tabla de "aprendizaje" que cuando encuentre "tal cosa" a la base suba Tal Cosa".

Saludos.


-----------------------------------
jsbsan
Viernes, 09 Septiembre 2016, 20:30

Re: Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas
-----------------------------------
Tincho:


[quote]y tener una tabla de "aprendizaje" que cuando encuentre "tal cosa" a la base suba Tal Cosa".[/quote]
Será interesante... puedes usar reglas...

Se puede hacer de varias formas, a lo mejor te sirve este programa que hice:
http://clasificaryordenar.blogspot.com.es/p/presentacion.html

La diferencia que en mi programa eran nombres y extensiones de archivos, y en el tuyo son datos de canciones.


-----------------------------------
tincho
Sabado, 10 Septiembre 2016, 16:12

Re: Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas
-----------------------------------
[quote user="jsbsan" post="34311"]Será interesante... puedes usar reglas...
Se puede hacer de varias formas, a lo mejor te sirve este programa que hice:
http://clasificaryordenar.blogspot.com.es/p/presentacion.html
La diferencia que en mi programa eran nombres y extensiones de archivos, y en el tuyo son datos de canciones.[/quote]
Puede ser útil algún tipo de reglas respecto al tratamiento de los nombres de archivos, como en tu programa, o algunas para quitar espacios o caracteres con acento o todo en minúsculas etc. todo lo que acote lo mas posible la repetición de información.
Volveré a echar un vistazo a tu programa.
Saludos.


-----------------------------------
tincho
Sabado, 10 Septiembre 2016, 16:16

Re: Insertar Un Registro En Sqlite En Una Tabla Que Usa Claves Foráneas
-----------------------------------
Luego de unas horas de análisis y de depuración del código logre hacer una función que mete los datos en una tabla teniendo en cuenta el tema de claves foráneas, y pregunta si agrega tal registro a la tabla accesoria si es que no existe (se puede puentear para que inserte a saco).
Lo dejo aca por si a alguien le sirve o le da ganas de mejorarla.

Saludos.

[code linenumbers=false syntax=gambas]
Public Sub ImportFileMetadata(conDat As Connection, strTab As String, stxReff As String[], stxVal As String[])

  Dim tblPri As Table ' Tabla primaria
  Dim tblSec As Table ' Tabla accesoria

  Dim fldPri As Field ' Tabla primaria
  Dim fldSecK As Field ' Campo Clave en tabla accesoria
  Dim fldSecN As Field ' Campo Nombre en tabla accesoria
  Dim strSQL As String
  Dim strSQLf As String
  Dim strSQLv As String
  Dim strSQLr As String ' PAra insertar registros en tablas foráneas

  Dim stxFld As New String[]
  Dim stxFldFK As New String[]
  Dim stxTblFK As New String[] ' matriz de nombres de Tablas foránelas
  Dim stxFldRK As New String[] ' matriz de Campos con las claves foránelas
  Dim stxFldNK As New String[] ' matriz de Campos con los nombres foránelos

  Dim intC As Integer
  Dim intK As Integer
  Dim resChk As Result
  Dim intFK As Integer
  Dim intD As Integer
  Dim resIns As Result
  Dim resUpd As Result

  Dim resInsRef As Result

  Dim strTmp As String

  Dim indIndx As Index ' Campo Nombre en tabla accesoria

  stxFldFK.Clear
  stxTblFK.Clear
  stxFldRK.Clear
  stxFldNK.Clear

  For Each strTmp In stxReff ' Creo las listas FK

    stxFldFK.Add(Split(strTmp, ".")[0])
    stxTblFK.Add(Split(strTmp, ".")[1])
    stxFldRK.Add(Split(strTmp, ".")[2])
    stxFldNK.Add(Split(strTmp, ".")[3])

  Next

  If conDat.Tables.Exist(strTab) = True Then

    tblPri = conDat.Tables[strTab]

    For Each fldPri In tblPri.Fields ' Creo la lista de campos
      stxFld.Add(fldPri.Name)
    Next

    For intC = 0 To stxVal.Max

      intK = stxFldFK.Find(stxFld[intC])

      If intK <> -1 Then ' Si el campo actual es referenciado busco el key en la tabla Foránea

        resChk = conDat.Exec("select " & stxFldRK[intK] & " from " & stxTblFK[intK] & " where " & stxFldNK[intK] & " = '" & stxVal[intC] & "'")

        If resChk.Available Then
          intFK = resChk[stxFldRK[intK]]

          If intFK <> Null Then
            Print stxVal[intC]
            stxVal[intC] = CStr(intFK)
          Endif
        Else ' Quiere decir que el registro no existe en la referencia

          If Message.Question(("El registro") & " " & stxVal[intC] & ": " & ("no existe en la tabla foranea"), ("Insertarlo"), ("Cancelar")) = 1 Then

            strSQLr = "insert into " & stxTblFK[intK] & "(" & stxFldRK[intK] & "," & stxFldNK[intK] & ") values(Null" & ",'" & stxVal[intC] & "')"

            resInsRef = conDat.Exec(strSQLr)
            Wait 0.1

            resChk = conDat.Exec("select " & stxFldRK[intK] & " from " & stxTblFK[intK] & " where " & stxFldNK[intK] & " = '" & stxVal[intC] & "'")

            If resChk.Available Then
              intFK = resChk[stxFldRK[intK]]

              If intFK <> Null Then
                Print stxVal[intC]
                stxVal[intC] = CStr(intFK)
              Endif
            Else ' Quiere decir que el registro no existe en la referencia
              Message.Info(("Tenes que insertar la referencia amano porque\nla forma automatica no funciono"))
            Endif

          Endif

        Endif

      Endif

    Next

  Endif

  ' Una vez que esta todo acomodado verifico si el registro existe o no
  resChk = conDat.Exec("select " & stxFld[1] & " from " & strTab & " where " & stxFld[1] & " = '" & stxVal[1] & "'")
  If resChk.Available Then
    ' El registro ya existe asi que procedo con un update

    resChk = conDat.Exec("select * from " & strTab & " where " & stxFld[1] & " = '" & stxVal[1] & "'")

    For intD = 2 To stxFld.Max
      If stxVal[intD] <> resChk[stxFld[intD]]
        strSQLv &= stxFld[intD] & "='" & stxVal[intD] & "',"
      Endif

    Next

    strSQL = "update " & strTab & " set " & strSQLv & " where " & stxFld[1] & " = '" & stxVal[1] & "'"
    strSQL = Replace(strSQL, "', where", "' where")

    If strSQLv = "" Then
      Print ("No hay cambios para aplicar")
    Else
      resUpd = conDat.Exec(strSQL)
    Endif

  Else
    'El registro no existe, así que procedo con un insert

    For intD = 0 To stxFld.Max

      Select intD
        Case 0
          strSQLf = "insert into " & strTab & "(" & stxFld[intD] & ","
          strSQLv &= "Null" & ","

        Case stxFld.Max
          strSQLf &= stxFld[intD] & ") values("

          Select tblPri.Fields[stxFld[intD]].Type
            Case 4, 7
              strSQLv &= stxVal[intD] & ")"
            Case 9
              strSQLv &= "'" & stxVal[intD] & "')"
          End Select

        Case Else

          strSQLf &= stxFld[intD] & ","

          Select tblPri.Fields[stxFld[intD]].Type

            Case 4, 7

              strSQLv &= stxVal[intD] & ","
            Case 9
              strSQLv &= "'" & stxVal[intD] & "',"
          End Select
      End Select

    Next
    strSQL = strSQLf & strSQLv
    resIns = conDat.Exec(strSQL)

  Endif

End
[/code]


