B4J Library [B4X] DBUtils 2

LucaMs

Expert
Licensed User
Longtime User
If I understand correctly, the use of PRAGMA is deprecated and my routine for obtaining the properties of fields uses it.

However, I have now created a new SQLite DB to test with a recent version of a tool and developed a test b4j project, which worked (it lists, for each table, table name and "all" the properties of each field).

I'd say I could add that function anyway.
 

OliverA

Expert
Licensed User
Longtime User
In version 2.06 (posted in post#1), there are two methods for B4A (ExecuteSpinner and ExecuteListView) and one for B4J (ExecuteTableView) that are surrounded with #If/#Else If/#End If compiler conditionals. The B4J compiler conditional is
B4X:
#Else If B4J
This produces an error when used in a NON_UI application (the TableView object is not available in a NON_UI application) and therefore should be changed to
B4X:
#Else If UI
I've not check out the unofficial version above to see if it has the same issue.
 

Xfood

Expert
Licensed User
I can't make this instruction work, can you have a correct example?
Thanks

B4X:
 TextReader1.Initialize(File.OpenInput(File.DirApp & "/db/", "ANAG.DAT"))
    line = TextReader1.ReadLine
    nRiga=nRiga +1
    Progress = Progress + 1
    ProgressBar1.Progress = Progress / TotalRec
    Label_Progress.Text = $"${NumberFormat(ProgressBar1.Progress,0,0)}%"$
Do While line <> Null
        Log(nRiga &"|" & line) 'write the line to LogCat
        line=line.Trim
        cEan=line.SubString2(1,13)
        cDescriz=line.SubString2(13,30)
        cUnMis = line.SubString2(43,46)
        cPzxC=line.SubString2(46,51)
        cPrezzo=line.SubString2(13,30)
        cRep=line.SubString2(13,30)
        cCodArt="00001"
        cIva="22"
        cCosto="0002000"
        cEsiste="20"
        
'////////////////////////////////////////////////////////
        Dim m As Map
        m.Initialize
        m.Put("ean", cEan)
        m.Put("codice", cCodArt)
        m.Put("DESCRIZ", cDescriz)
        m.Put("Um", cUnMis)
        m.Put("pzxc", cPzxC)
        m.Put("Prezzo", cPrezzo)
        m.Put("rep", cRep)
        m.Put("Iva", cIva)
        m.Put("Costo", cCosto)
        m.Put("ESISTE",cEsiste)
        m.Put("id",Null)
        arc.Add(m)
        line = TextReader1.ReadLine
        nRiga=nRiga +1
        Loop

    TextReader1.Close
    Log("Inserisco i dati in anagrafica")
    Label1.Text="Inserisco i dati nel db"
    Log("SCRITTURA IN CORSO....")
    DBUtils.InsertOrUpdateMaps(Sql1, "anag", "ean",arc)
    CloseDB
    
    
  '' log 
''    SELECT [ean] FROM [anag] WHERE [ean] = '031195000041'
''    value_exists: (Map) Not initialized
. ExecuteMap: SELECT [ean] FROM [anag] WHERE [ean] = '000000855555'
' No records found.'
 

Toky Olivier

Active Member
Licensed User
Longtime User
What exactly is your issue?

If this is the log:
'' log '' SELECT [ean] FROM [anag] WHERE [ean] = '031195000041' '' value_exists: (Map) Not initialized . ExecuteMap: SELECT [ean] FROM [anag] WHERE [ean] = '000000855555' ' No records found.'

What I see is that you tried to set [ean] field with the value "031195000041" but you use another value "000000855555" when you check the record in the table? Or I'm wrong? If it's like that, it's normal that you cannot find any record. Try to excecute "SELECT * FROM [anag]" to see all record in the table.

PS: Now, I'm not sure also if the manner I used to implement "Insert or Update" is right. Performance will not be good with many records. May be it's better to use UPSERT syntax: https://www.sqlite.org/lang_UPSERT.html

Edit: UPSERT syntax was only introduced on the version 3.24 issued on 2018-06-04 (https://www.sqlite.org/changes.html). May be finally it's not a good idea to use it now.
 
Last edited:

Xfood

Expert
Licensed User
you have an example of upsert b4j/b4a?
 

Toky Olivier

Active Member
Licensed User
Longtime User
you have an example of upsert b4j/b4a?
As I said, it's not a good idea to use Upsert finally, better use "INSERT OR REPLACE".
B4X:
Sub Button1_Click
    If EditText1.Text.Trim = "" Then
        ToastMessageShow("Key shouldn't be empty", True)
        Return
    End If
    
    sql.ExecNonQuery2("INSERT OR REPLACE INTO mytable (mykey, myvalue) VALUES (?, ?)", _
                      Array As String(EditText1.Text, EditText2.Text))
    
    EditText1.Text = ""
    EditText2.Text = ""
End Sub

Enclosed a sample b4a project.
 

Attachments

  • InsertOrReplace.zip
    14.4 KB · Views: 440

Xfood

Expert
Licensed User
Thanks for replying, so I don't have to specify the key field for "INSERT OR REPLACE"? if I wanted to use a map with the INSERT OR REPLACE command, I can modify the existing original map like this:
'sb.Append("INSERT INTO [" & TableName & "] (")
sb.Append("INSERT OR REPLACE INTO [" & TableName & "] (") ' <---------- MODIFICA


B4X:
Public Sub InsertMaps(SQL As SQL, TableName As String, ListOfMaps As List)
    Dim sb, columns, values As StringBuilder
    'Small check for a common error where the same map is used in a loop
    If ListOfMaps.Size > 1 And ListOfMaps.Get(0) = ListOfMaps.Get(1) Then
        Log("Same Map found twice in list. Each item in the list should include a different map object.")
        Return
    End If
    SQL.BeginTransaction
    Try
        For i1 = 0 To ListOfMaps.Size - 1
            sb.Initialize
            columns.Initialize
            values.Initialize
            Dim listOfValues As List
            listOfValues.Initialize
          'sb.Append("INSERT INTO [" & TableName & "] (")
          sb.Append("INSERT OR REPLACE INTO [" & TableName & "] (")     ' <---------- MODIFICA
            Dim m As Map = ListOfMaps.Get(i1)
            For Each col As String In m.Keys
                Dim value As Object = m.Get(col)
                If listOfValues.Size > 0 Then
                    columns.Append(", ")
                    values.Append(", ")
                End If
                columns.Append(EscapeField(col))
                values.Append("?")
                listOfValues.Add(value)
            Next
            sb.Append(columns.ToString).Append(") VALUES (").Append(values.ToString).Append(")")
            If i1 = 0 Then Log("InsertMaps (first query out of " & ListOfMaps.Size & "): " & sb.ToString)
            SQL.ExecNonQuery2(sb.ToString, listOfValues)
        Next
        SQL.TransactionSuccessful
    Catch
        Log(LastException)
        #If B4i OR B4J
        SQL.Rollback
        #End If
    End Try
#If B4A
    SQL.EndTransaction
#End If
End Sub
 

Toky Olivier

Active Member
Licensed User
Longtime User
You should have UNIQUE or PRIMARY KEY in your table to be able use INSERT OR REPLACE.
Then you use it only like you use INSERT.

What error you get with this modification?
 

Xfood

Expert
Licensed User
You should have UNIQUE or PRIMARY KEY in your table to be able use INSERT OR REPLACE.
Then you use it only like you use INSERT.

What error you get with this modification?
I haven't tried it yet, I wanted to know if it was correct to do so.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…