Italian Problemi con l'ID di un database in sql

toro1950

Active Member
Licensed User
Buona serata tutta la comunità, è la prima volta che mi trovo alle prese con un database, grazie a qualche esempio scaricato dal forum e grazie all'aiuto del grande Sagenut sono riuscito in qualche modo a farlo funzionare e visualizzarlo tramite una CustomView Il problema per me è che i dati devono essere visualizzati per il giorno di inserimento, praticamente è un agenda per appuntamenti; selezionando il giorno da un calendario si può scegliere l'ora per l'inserimento e visualizzare i dati già presenti inseriti in altri orari. Tutto questo, che sembra difficile, sono riuscito a farlo ma non riesco a fare una cosa che dovrebbe essere banalissima, modificare un record o eliminarlo. Cerco di spiegarmi al meglio: selezionato il giorno, tramite una query, la CustomView viene popolata con i dati del giorno, ma non viene visualizzata, il software preleva questi dati e li visualizza insieme ad una grafica appropriata da far capire all'utente le ore che ha a disposizione. può capitare che l'appuntamento deve essere spostato o cancellato, per far questo cliccando sull'appuntamento vengono riempite le relative editext coni dati già salvati, al momento che si cerca di sovrascrivere il record, un controllo avvisa che già esiste e se si è sicuri di sovrasrriverlo, a si questo non viene fatto e l'app esce. Per quello che ho capito è che devo recuperare l'Id del record. Sul pc nel database viene aggiunto un campo con l'Id con l'autoincremento, quindi quando si seleziona un record può essere visualizzato, in caso di nuovo inserimento la relativa casellina di testo è vuota altrimenti contiene l'Id e da qui capire se aggiungere o sovrascrivere è facile. Ritornado a B4A negli esempi che ho scaricato non viene aggiunto il campo dell'Id ma viene calcolato.
esempio inserimento record
RowID = SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM p????????")
RowIDList.Add(RowID)
CurrentIndex = RowIDList.Size - 1
txtID.Text = " " & RowID
e questo non sono prprio riuscito a capirlo, forse per uno nuovo si (maxrowid) Nella CustomView ho aggiunto un'altra label che dovrebbe contenere l'Id per ogni record, come fare a recuperare questo dato durante la query? in questo modo sarebbe facile modificare o eliminare un record
Esiste la possibilità di insere il campo ID con autoincremento?
Mario
 

LucaMs

Expert
Licensed User
Longtime User
In SQLite esiste il campo "rowid", di default, che è autoincrementato ed è un campo particolare. In altri DBMS non esiste.
Nella tua CLV potresti aggiungere una Label lblRowId NON visibile per ogni record, recuperarne il valore in base al click sull'Item ed eseguire modifiche o eliminazioni.
Se non usi il Value associato ad ogni Item della CLV, magari usalo per valorizzarlo col rowid (invece della Label).

Esiste la possibilità di insere il campo ID con autoincremento?
Non è necessario (né consentito) "inserire il rowid", viene creato ed aggiunto automaticamente al record quando esegui una query Insert.
 
Last edited:

toro1950

Active Member
Licensed User
Grazie della risposta Luca, ma non ho ben capito a cosa potrebbe servirmi la lista se con una query cerco un determinato record, una volta trovato non sapendo la posizione come faccio a recuperare il RowID se devo modificarlo o eliminarlo? Non c'è un modo diretto per leggere il RowID insieme agli altri campi? se cosi non fosse ( 😢) aggiungo io un campo Id e prima dell'inserimento di un nuovo record recupero il RowID con SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM p????????"), lo aumento di 1 e lo salvo nel campo Id, in questo modo evito la lista ed ho a disposizione sempre il RowID o sbaglio?
 

LucaMs

Expert
Licensed User
Longtime User
a cosa potrebbe servirmi la lista
Benché in genere bisognerebbe mantenere separati dati-logica dall'interfaccia grafica, puoi fare a meno di una lista di ID (rowid, in questo caso, visto che usi SQLite).

Tu dovrai scrivere la query di inserimento SENZA passare un valore per rowid, che verrà aggiunto automaticamente dal motore di SQLite.
Non ti servirà nemmeno cercare il max(rowid), dato che appunto sarà SQLite ad incrementare il valore di rowid automaticamente, ad ogni nuovo record inserito.
Quando dovrai visualizzare i record nella CLV:

Dim RowID As Int

All'interno del ciclo (Do While RS.NextRow):

a - leggi il primo record - usa "SELETCT rowid, * FROM..."
b - crei il panel base (diciamo pnlItem - B4XView) dell'item, carichi il layout dell'item e riempi le view con i dati del record corrente (RS.Get...)
c - infine aggiungi il panel alla CLV:
d - RowID = RS.GetInt("rowid")
CLV.Add(pnlItem, RowID)
e - lettura record successivo (Loop)

Quando scrivi la query d'inserimento, NON passare dati per il campo "rowid", solo gli altri.
Nell'evento Click della CLV avrai:
B4X:
Private Sub CLV_ItemClick (Index As Int, Value As Object)
    Dim RowID As Int = Value
    ' Userai RowID per aggiornamento/eliminazione del record selezionato dall'utente col click
End Sub


P.S. Meglio così, avere una funzione separata che crei l'item della CLV:
B4X:
' RS = .... SELECT rowid, * FROM ...
Do While RS.NextRow
    CLV.Add(CreaItem(RS), RS.GetInt("rowid"))
Loop
RS.Close

Nella CreaItem, funzione che restituisce una B4XView che è un panel o pane, fai come scritto sopra, carichi il layout e riempi le sue view con i dati del RS, infine restituisci il pnlItem.
 
Last edited:

toro1950

Active Member
Licensed User
Buona giornata a tutti, Luca ti ringrazio per i tuoi consigli, però per la mia piccola prepazione è arabo, io ho esperienza su database sql su pc e non su app,
quindi non riuscendo a recuperare il RowID di un record selezionato da una query, ho cercato di fare quello che ti avevo accennato, ho aggiunto un campo al database contenente il rowid, recuperando questo con (SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM mytabella) prima di inserire un nuovo record. questo funziona perfettamente ma ha un grosso grande problema ; se dato quando il database è stato solo inizializzato e non ha record manda in blocco l'App, non restituisci 0, 😢 il che non mi sembra una cosa normale. Potrebbe essere superato inserendo subito un record e dando come id 1, dovrebbe uscire un messaggio alla prima esecuzione dell'app di inserire subito un recrrd, è una pessima e non praticabile soluzione, esiste un qualcosa per capire che il database è vuoto, ho pensato ad una query ma non mi viene in mente come impostarla ?
 

LucaMs

Expert
Licensed User
Longtime User
SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM mytabella)
Anche la tua, sopra, dovrebbe funzionare (manca il doppio apice finale, ma forse hai scritto qui direttamente, non fatto copia e incolla dal tuo progetto), ma non ho provato (con tabelle vuote).
Forse restituisce Null, anziché zero?
Vediamo...
Prova così:
B4X:
Dim RowID As Int
Dim objRowID As Object
objRowID= SQL1.ExecQuerySingleResult("SELECT max(rowid) FROM mytabella")
If Not(objRowID = Null) Then
    RowID = objRowID
Else
    RowID = 0
End If

Se usi SQLite, esiste già un campo di nome "rowid", quindi magari il tuo chiamalo "id".

(Riporta sempre qui i messaggi d'errore)
 

LucaMs

Expert
Licensed User
Longtime User
ma non ho provato (con tabelle vuote).
Forse restituisce Null, anziché zero?
Ho provato ed è proprio come sopra, quindi la seguente funzione... funziona:
B4X:
Public Sub GetLastID(TableName As String) As Int
    Dim Query As String
    Dim ID As Int
    Dim objID As Object
    Query = $"Select MAX('ID') FROM '${TableName}'"$
    objID = gDB.ExecQuerySingleResult(Query)
    If Not(objID = Null) Then
        ID = objID
    Else
        ID = 0
    End If
    Return ID
End Sub

(gDB è ovviamente l'oggetto SQL)

Oh, è chiaro che se vuoi usare il tuo ID ed aggiunge 1 ogni volta che inseririsci un nuovo record, ID NON deve essere dichiarato come autoincrementato.
 

toro1950

Active Member
Licensed User
Sono ancora nei guai, il codice per eliminare un record funziona perfettemante quello per sovrascrivrre fa uscire l'app, dove sbaglio? riporto il codice. l'Id in ambo i casi è sempre lo stesso, viene letto nel record stesso. Purtroppo non ho capito come lasciare il codice originale, appena lo inserisco me lo cambia in italiano, penso che si capisce uguale
B4X:
Pulsantedelete_clic
    Query privata come stringa
    Dim sf As Object = xui.Msgbox2Async("Vuoi realmentee eliminare la prenotazione di " & editnome.Text , "richiesta", "Si", "", "No", Null)
    Attendi (sf) Msgbox_Result (risultato come int)
  if Result = xui.DialogResponse_Positive then
        Query = "DELETE FROM prenota WHERE rowid = " & Id
        SQL1.ExecNonQuery(Query)   
        resetgrafica   
        resettaorario                          
      Updategiorno
  end if
Fine sott


Pulsante registra_Click
   
    Dim query come stringa
    
    Query = "SELECT * FROM prenota WHERE nome = ? AND danascita = ? AND datapren = ?"
    ResultSet1 = SQL1.ExecQuery2(Query, Array As String (modificanome.Testo, modificaNascita.Testo, modificapren.Testo))
    
    Se ResultSet1.NextRow = True then
        Msgbox2Async("La prenotazione è già esistente, vuoi cambiare l'orario o il giorno?", "Richiesta", "Si", "", "No", Null, False)
               Attendi Msgbox_Result (risultato come int)

      if risultato = DialogResponse.POSITIVE Allora
        if comboprestazioni.SelectedIndex=0 then te= Mod3.temp1
          if comboprestazioni.SelectedIndex=1 then te = Mod3.temp2
      if comboprestazioni.SelectedIndex=2 thente= Mod3.temp3
            testo=Id
                
            Query = "UPDATE prenota set nome = ?, dapren = ?, orario = ?, prestazioni = ?, tempo = ?, danascita = ?, idpren= ? WHERE rowid = " & Id
            SQL1.ExecNonQuery2(Query, Array As String(editnome.Text, editpren.Text, combora.SelectedItem, comboprestazioni.SelectedItem, te, EditNascita.text, testo))
            
            ToastMessageShow ("registrato",False)'
            updategiorno
        
  else
        
  end if
        
    
else
'inserisce nuovo record che funziona perfettamente
        end if
        
        '[/CODICE]
 

Sagenut

Expert
Licensed User
Longtime User
Purtroppo non ho capito come lasciare il codice originale, appena lo inserisco me lo cambia in italiano, penso che si capisce uguale
Devi avere attivato la traduzione automatica nel browser (Chrome, Firefox... Quel che usi).
O disattivi la tradizione automatica o succede così.
 

toro1950

Active Member
Licensed User
Buona serata, Risoltooooooooooooooooo!!!!!!!!!! ricontrollando attentamente ho scoperto che ho fatto un errore sul nome di un campo, corretto tutto si è risolto.
Voglio ringraziare Luca per la soluzione che ho dato per SELECT max(rowid) FROM mytabella che si bloccava in assenza di dati. Grazie Luca!!
Mario
 
Top