Italian Copiare record da un db all'altro

AlpVir

Well-Known Member
Licensed User
Longtime User
Dovrei copiare qualche record da un db sqlite ad un altro db sqlite.
La procedura "lunga" prevede qualcosa del genere
B4X:
rs=dbSorgente.ExecQuery("SELECT * FROM TabSorgente WHERE Condizione=123")
For i=0 To rs.RowCount-1
       rs.Position=i
       Criterio="INSERT INTO TabSorgente (Campo1,Campo2,Campo3) VALUES (" & rs.GetInt("Campo1") & ",'" & rs.GetString("Campo2") & "','" & rs.GetString("Campo3") & "')"
       dbDestinazione.ExecNonQuery(Criterio)
 Next

Siccome i campi sono numerosi, dal nome più "ostrogoto" di Campo1, Campo2, ecc. ed inoltre sono di diverso tipo (interi, stringhe, long, ecc.) mi chiedevo se esiste un sistema più valido di quello da me scritto, assai laborioso da scrivere.
Grazie per l'attenzione.
 

AlpVir

Well-Known Member
Licensed User
Longtime User
Non è assolutamente un problema di velocità.
E' solo che mi pare non elegante adottare la soluzione di cui al post #1 che elenca una serie di nomi di campi e, successivamente, il loro valore.
Ma se non esiste uno o più specifici statment che condensano queste istruzioni, mi rassegnerò a scrivere lunghe righe di codice.
 

LucaMs

Expert
Licensed User
Longtime User
Non è assolutamente un problema di velocità.
E' solo che mi pare non elegante adottare la soluzione di cui al post #1 che elenca una serie di nomi di campi e, successivamente, il loro valore.
Ma se non esiste uno o più specifici statment che condensano queste istruzioni, mi rassegnerò a scrivere lunghe righe di codice.
Beh, puoi evitare di dover costruire la query in quel modo, con virgolette varie, usando le versioni 2 delle query (ExecNonQuery2), ovvero le query parametrizzate, che hanno anche altri grossi vantaggi.

Anche AddNonQueryToBatch è parametrica
 

marcellissimo

Member
Licensed User
Longtime User
se lo schema è identico puoi usare
B4X:
txt=$"insert into  ${DbTabellaSorgente} select * from ${DBTempTable}   "$ ' where EVENTUALI CONDIZIONI"$
    sql1.ExecNonQuery(txt)
 

AlpVir

Well-Known Member
Licensed User
Longtime User
Il posto di marcellissimo pare (quasi) risolutivo ma non capisco 2 cose.
Devo inserire questa istruzione all'interno di un ciclo FOR NEXT ?
B4X:
dim W as SQL   ' originale
Dim C  as SQL  ' copia
dim rs  as cursor
W.Initialize (File.DirRootExternal,GlobalNomeDataBase,False)
C.Initialize (File.DirRootExternal,GlobalNomeDataBase_copia,False)
rs=W.ExecQuery("SELECT * FROM Tabella1")
For i=0 To rs.RowCount-1
        rs.Position=i
        txt=$"insert into  ${C} select * from ${W}"$
        C.ExecNonQuery(txt)
        Log(rs.GetString("Nome"))
Next
rs.Close
W.Close
C.Close
oppure è sufficiente
B4X:
dim W as SQL   ' originale
Dim C  as SQL  ' copia
W.Initialize (File.DirRootExternal,GlobalNomeDataBase,False)
C.Initialize (File.DirRootExternal,GlobalNomeDataBase_copia,True)
txt=$"insert into  ${C} select * from ${W}"$
C.ExecNonQuery(txt)
W.Close
C.Close
In entrambi i casi non funziona, anche se scrivo
B4X:
txt=$"insert into  ${Tabella1} select * from ${Tabella1}"$
Sì, i due db hanno tabelle e strutture identiche.
 

marcellissimo

Member
Licensed User
Longtime User
prova così


B4X:
    If File.Exists(File.DirDefaultExternal, "db1.db")=False Then
  


        File.Copy(File.DirAssets, "db1.db", File.DirDefaultExternal, "db1.db")
    End If
  
  
  
  
  
    If File.Exists(File.DirDefaultExternal, "db2.db")=False Then
  

        File.Copy(File.DirAssets, "db2.db", File.DirDefaultExternal, "db2.db")
    End If
  
  
    Dim DBFilePath As String    = File.Dirdefaultexternal
    Dim DBFileName As String="db1.db"
  
    If sql1.IsInitialized =False Then
        sql1.Initialize(DBFilePath,DBFileName,False)
    End If
'
    Dim txt As String
    Dim DbTabellaSorgente As String="unaTabella"
    Dim DbDestinazione As String="db1.db"
    Dim DBTempTable As String="TabSorgente"

    txt="ATTACH DATABASE '" & File.Combine(DBFilePath,DbDestinazione)  & "' AS SORGENTE"
    sql1.ExecNonQuery(txt) 
  

  
    
    txt="CREATE TEMPORARY TABLE IF NOT EXISTS  " & DBTempTable & " AS SELECT * " _
    & "FROM  DESTINAZIONE." & DbTabellaSorgente
    sql1.ExecNonQuery(txt) 
  

  
    txt="CREATE TABLE IF NOT EXISTS DESTINAZIONE." & DBTempTable & " AS SELECT * " _
    & "FROM " & DbTabellaSorgente
    sql1.ExecNonQuery(txt) 
  
      
    txt=$"insert into  ${DbTabellaSorgente} select * from ${DBTempTable}   "$ ' where EVENTUALI CONDIZIONI"$
    sql1.ExecNonQuery(txt)




    '    txt="DROP TABLE IF EXISTS SORGENTE." & TabSorgente
'    sql1.ExecNonQuery(txt)
    '
  
''''''''''tralascia 
    Dim sql As String =funzione("unaTabella")
    Log(sql)
'''''''''''''
End Sub
Sub funzione(table As String)
Dim    txt As String=$"PRAGMA table_info(${table})"$
Dim c As Cursor=sql1.ExecQuery(txt)
Dim stringa As String=""
Dim apici="'"
Dim n As Int =c.RowCount-1
For i =0 To n
    c.position=i
If c.GetInt("pk")<>1 Then
        If c.getstring("type")<>"INTEGER" Then
            stringa=stringa & apici & c.GetString("name") & apici  & ", "
        Else
                stringa=stringa & c.GetString("name")   & ", "
              
        End If
End If
Next
c.Close


    Dim strSql  As String = stringa.SubString2(0,stringa.length-2)
    Log (strSql)
  
Return strSql

End Sub
no, nessun ciclo il recordset viene copiato pari pari...
il problema è che se c'è una chiave primaria nella tabella di destinazione ti darà errore, c'è una funzione qui sopra che ti crea una parte di stringa sql che esclude il campo chiave... in questo caso c'è da lavorare ancora un pò
 
Last edited:

AlpVir

Well-Known Member
Licensed User
Longtime User
Comincio a non capire più nulla. La tua proposta al post #12 è assai complicata. Quella al post #9 mi pare semplice e compatta.
A me pare che l'errore sia nell'applicare al mio caso dell'istruzione
txt=$"insert into ${DbTabellaSorgente} select * from tmp_${DBTempTable}
DbTabellaSorgente e DBTempTable sono dimensionati come SQL oppure sono delle tabelle del db ?
 

marcellissimo

Member
Licensed User
Longtime User
il problema, secondo me, è il fatto che sono due db diversi, quella funzione compatta funziona sicuramente sullo stesso db, quella al 12 funziona sicuramente su due db diversi...
 

sirjo66

Well-Known Member
Licensed User
Longtime User
con la query
INSERT into Tabella1 select * from Tabella2 where ...
non hai bisogno del ciclo FOR, fa tutto lei in un colpo solo,
ma funziona solo se Tabella1 e Tabella2 fanno parte dello stesso database
 

sirjo66

Well-Known Member
Licensed User
Longtime User
.... comunque molto interessante il codice di Marcellissimo al post #11

Mi sembra di capire che prima di tutto apre un database assegnandolo alla variabile sql1 e poi con il comando ATTACH DATABASE gli "attacca" il secondo database, potendolo quindi gestire sempre da sql1
In questo modo è come se le tabelle facessero parte dello stesso database e quindi si può usare il comando del mio post precedente e diverrebbe quindi tutto molto semplice.
L'unica cosa è che nel codice di Marcellissimo si fa una confusione tremenda tra la tabella sorgente e quella di destinazione per cui il codice andrebbe risistemato.
 
Last edited:

udg

Expert
Licensed User
Longtime User
Ammesso che user1 abbiamo permessi su DB1 e DB2, non sarebbe possibile qualcosa tipo:
INSERT into DB1.Tabella1 select * from DB2.Tabella2 where ... ?

Ho visto tempo fa anche qualcosa come SELECT INTO
Select * into db1.Tabella1 from db2.Tabella2


Non so se siano applicabili e non ho provato nulla. Era giusto per aggiungere una possibilità..
 

marcellissimo

Member
Licensed User
Longtime User
Mi sembra di capire che prima di tutto apre un database assegnandolo alla variabile sql1 e poi con il comando ATTACH DATABASE gli "attacca" il secondo database, potendolo quindi gestire sempre da sql1
In questo modo è come se le tabelle facessero parte dello stesso database e quindi si può usare il comando del mio post precedente e diverrebbe quindi tutto molto semplice.
Si in teoria dovrebbe andare così ma di fatto non sono riuscito ad usare la tabella in questo modo, ho dovuto copiare la tabella sorgente in una tabella TEMPORARY nel db di destinazione e solo dopo riversare i recordset.

Senza inserire il codice perchè poi rischio di fare pasticci, i comandi che funzionano testati su sqliteStudio sono :

1)ATTACH DATABASE 'unDbSorgente.db' As SORGENTE

2)CREATE TEMPORARY TABLE IF NOT EXISTS TMP_tabellaDaCopiare AS SELECT *
FROM SORGENTE.tabellaDaCopiare

3)INSERT INTO tabellaDbDestinazione select * from TMP_tabellaDaCopiare --a patto che le tabelle siano uguali


L'unica cosa è che nel codice di Marcellissimo si fa una confusione tremenda tra la tabella sorgente e quella di destinazione per cui il codice andrebbe risistemato.
Verissimo :(

Aggiungo che se le due tabelle hanno una chiave primaria, anche se la tabella di destinazione è vuota, va in errore(correggetemi se sbaglio) io per un problema
simile ho risolto usando un contatore esterno, pessima soluzione ma in mancanza d'altro...

#rettifico

1)ATTACH DATABASE 'unDbSorgente.db' As SORGENTE

2)INSERT INTO tabellaDbDestinazione select * from SORGENTE.tabellaDaCopiare --a patto che le tabelle siano uguali

funziona anche così.
 
Last edited:
Top