Android Tutorial DBUtils - Android databases are now simple!

Tonycompu

Member
Hello,

I'm testing the code but something strange is happening.

I have my db with a table called tblSetting and a single row. I'm trying to use this code

B4X:
     SQL.Initialize(File.DirInternal, "Data.db", True)
    'Load initial setting
    Dim m As Map
    m = DBUtils.ExecuteMap(SQL, "SELECT * FROM tblSetting", Null)
    If m <> Null Then 
        lblLabel1.Text = m.Get("Field1")
        lblLabel2.Text = m.Get("Field2")
    End If

but I got this error:
** Activity (main) Create, isFirst = true **


Error occurred on line: 0 (dbutils)
android.database.sqlite.SQLiteException: no such table: tblSetting (code 1): , while compiling: SELECT * FROM tblSetting


at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
at anywheresoftware.b4a.sql.SQL.ExecQuery2(SQL.java:167)
at anywheresoftware.b4a.sql.SQL.ExecQuery(SQL.java:155)


at b4a.example.dbutils._executemap(dbutils.java:39)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:302)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
at b4a.example.main.afterFirstLayout(main.java:98)
at b4a.example.main.access$100(main.java:16)
at b4a.example.main$WaitForLayout.run(main.java:76)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

But something more strange is happening when I use this code

B4X:
    'Create the students table which holds data about each student.
    Dim m As Map
    m.Initialize
    m.Put("Id", DBUtils.DB_TEXT)
    m.Put("First Name", DBUtils.DB_TEXT)
    m.Put("Last Name", DBUtils.DB_TEXT)
    m.Put("Birthday", DBUtils.DB_INTEGER)
    DBUtils.CreateTable(SQL, "Students", m, "Id")

The app run fine but no table is created.

What's wrong with this.

Please help.
 

Attachments

  • bd.jpg
    42.5 KB · Views: 447

Tonycompu

Member
You need to add the db file to the Files tab in the IDE and then copy it with DBUtils.CopyDBFromAssets

Ok, I've added the db file to the Files tab and I did this change:
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim TargetDir As String
    If FirstTime Then
      TargetDir = DBUtils.CopyDBFromAssets("Data.db")
     SQL.Initialize(TargetDir, "Data.db", True)
    End If
   
    Dim m As Map
    m = DBUtils.ExecuteMap(SQL, "SELECT * FROM tblSetting", Null)
    If m <> Null Then 
        label1.Text = m.Get("Field1")
        label2.Text = m.Get("Field1")
    End If
End Sub

and still it isn't working. I got the same error : "android.database.sqlite.SQLiteException: no such table: tblSetting (code 1): , while compiling: SELECT * FROM tblSetting"
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
There are two options:
1. There is no such table in your database.
2. There is already an existing empty database file from your previous attempts so the new database is not copied (DBUtils.CopyDBFromAssets will not overwrite an existing database).

You can delete it with File.Delete(File.DirDefaultExternal, "Data.db"). Run it before you call CopyDBFromAssets.
 

Tonycompu

Member

Excelent. Option 2 was it.

Thanks

But, Now I have another issue. it isn't reading the field info, I'm getting NULL in label1 and label2 even though m is not NULL, it seems that
m.Get("Field1") is not getting the value. I've double checked the field names and they are ok.

how can I fix this ?

thank again
 

Tonycompu

Member
Never mind. I've fixed it.

I found the solution in the DBUtils sample: 'keys are lower cased!

Thank you Erel, you're doing a great job.
 

Hubert Brandel

Active Member
Licensed User
Longtime User
Hi,

the function CreateTable() is surly usefull for peoble used to handle SQL servers with NULL values,
but in most cases a DEFAULT "" for TEXT or 0 with numeric fields is better in handling.
So I wrote this function, maybe you want to add this to the lib ?

B4X:
Sub CreateTableDefault(SQL As SQL, TableName As String, FieldsAndTypes As Map, PrimaryKey As String)
   Dim sb As StringBuilder
   sb.Initialize
   sb.Append("(")
   For i = 0 To FieldsAndTypes.Size - 1
     Dim field, ftype As String
     field = FieldsAndTypes.GetKeyAt(i)
     ftype = FieldsAndTypes.GetValueAt(i)
     If i > 0 Then sb.Append(", ")
     sb.Append("[").Append(field).Append("] ").Append(ftype)
     If field = PrimaryKey Then
       sb.Append(" PRIMARY KEY")
     Else
       Select ftype
         Case DBUtils.DB_TEXT                 : sb.Append(" DEFAULT '' ")
         Case DBUtils.DB_REAL, DBUtils.DB_INTEGER    : sb.Append(" DEFAULT 0 ")
         Case DBUtils.DB_BLOB  : sb.Append(" DEFAULT '' ") ' is this usefull ???
       End Select   
     End If     
   Next
   sb.Append(")")
   Dim query As String
   query = "CREATE TABLE IF NOT EXISTS [" & TableName & "] " & sb.ToString
   Log("CreateTable: " & query)
   SQL.ExecNonQuery(query)
End Sub
 

AHilberink

Active Member
Licensed User
Longtime User
Hi,

I needed to export to XML, so I made an extra function. May be also usefull for sombody else?

B4X:
'Executes the given query and creates a List that you can save as XML using File.WriteList(x,x,x)
'This code won't work with BLOB fields. Putting all BLOB fields at the end of the record and increase
'the -1 of the line "For i = 0 To cur.ColumnCount - 1" with the number of BLOB fields is an option.
Sub ExecuteXML (SQL As SQL, Query As String, StringArgs() As String, Limit As Int) As List
    Dim table As List
    Dim name, value As String
    Dim cur As Cursor
    If StringArgs <> Null Then
        cur = SQL.ExecQuery2(Query, StringArgs)
    Else
        cur = SQL.ExecQuery(Query)
    End If
    Log("ExecuteXML: " & Query)
    If Limit > 0 Then Limit = Min(Limit, cur.RowCount) Else Limit = cur.RowCount

    table.Initialize
    table.Add("<?xml version="&Chr(34)&"1.0"&Chr(34)&" encoding="&Chr(34)&"UTF-8"&Chr(34)&"?>")
    table.Add("<Table>")
    For row = 0 To Limit - 1
        cur.Position = row

        table.Add("<Record>")
        For i = 0 To cur.ColumnCount - 1
            value=EscapeXML(cur.GetString2(i))
            name=cur.GetColumnName(i)
            If(value=Null) Then
                table.add("<"&name&"></"&name&">")
            Else
                table.add("<"&name&">"&value&"</"&name&">")
            End If
        Next
        table.Add("</Record>")
    Next
    cur.Close
    table.Add("</Table>")
    Return table
End Sub

Sub EscapeXml(Raw As String) As String
  Dim sb As StringBuilder
  sb.Initialize
  For i = 0 To Raw.Length - 1
    Dim c As Char = Raw.CharAt(i)
    Select c
      Case QUOTE
         sb.Append("&quot;")
      Case "'"
         sb.Append("&apos;")
      Case "<"
         sb.Append("&lt;")
      Case ">"
         sb.Append("&gt;")
      Case "&"
         sb.Append("&amp;")
      Case Else
         sb.Append(c)
    End Select
  Next
  Return sb.ToString
End Sub
 
Last edited:

RVP

Active Member
Licensed User
Longtime User
I have added a ExecuteMapList to this It returns a List of Maps.


B4X:
Sub ExecuteMapList(SQLAsSQL, Query AsString, StringArgs() AsString, Limit AsInt) As List
Dim cur As Cursor
If StringArgs <> Null Then
cur = SQL.ExecQuery2(Query, StringArgs)
Else
cur = SQL.ExecQuery(Query)
End If
Log("ExecuteMemoryTable: " & Query)
Dim TableList As List
TableList.Initialize
If Limit > 0 Then Limit = Min(Limit, cur.RowCount) Else Limit = cur.RowCount
For row = 0 To Limit - 1
cur.Position = row
Dim res As Map
res.Initialize
Dim values(cur.ColumnCount) AsString
For col = 0 To cur.ColumnCount - 1
Try
res.Put(cur.GetColumnName(col).ToLowerCase, cur.GetString2(col))
Catch
Dim byt() AsByte: byt = cur.GetBlob2(col)
res.Put(cur.GetColumnName(col).ToLowerCase, BytesToString(byt,0,byt.Length,"UTF8"))
End Try
Next
TableList.Add(res)
Next
cur.Close
Return TableList
End Sub

Used like this

B4X:
Dim TimeList As List
TimeList.Initialize
TimeList = DBUtils.ExecuteMapList(Main.SQL1,SQLScripts.UploadTimeList(WO),Null,0)

For cntr = 0 To TimeList.Size-1
        Dim TimeMap As Map
        TimeMap.Initialize
        TimeMap = TimeList.Get(cntr)
txtWO.text = TimeMap.Get("wdnum")
' etc

Next
 
Last edited:

mkvidyashankar

Active Member
Licensed User
Longtime User
I am trying to update a single record using this code

B4X:
  Dim recno As Int
    recno=dbcursor.GetInt("slno")
        Dim m As Map
        m.Initialize
        Dim WhereFieldEquals As Map
        WhereFieldEquals.Initialize
        WhereFieldEquals.Put("slno", recno)
        DBUtils.UpdateRecord(sql1, "table2","fav","yes" , WhereFieldEquals)
        ToastMessageShow("Added to your favourites Successfully",True)


but the database is not updating, please help
 

LucaMs

Expert
Licensed User
Longtime User
Unless it is changed, UpdateRecord should receive these parameters:

DB (SQL type);
TableName (String)
FIELDS (MAP)
WhereFieldEquals (Map)

Then you should use:
B4X:
Dim recno As Int
recno = dbcursor.GetInt("slno")

Dim Fields As Map
Fields.Initialize
Fields.Put("fav", "yes)

Dim WhereFieldEquals As Map
WhereFieldEquals.Initialize
WhereFieldEquals.Put("slno", recno)

DBUtils.UpdateRecord(sql1, "table2", Fields, WhereFieldEquals)

ToastMessageShow("Added to your favourites Successfully",True)
 

mkvidyashankar

Active Member
Licensed User
Longtime User

Thanks LucaMs for quick reply
i have given these parameters in the code
is there any thing wrong, could you please explain
Thanks in advance
 

LucaMs

Expert
Licensed User
Longtime User
The code in your post was:
B4X:
DBUtils.UpdateRecord(sql1, "table2","fav","yes" , WhereFieldEquals)

If you have a field "fav" and you want to set its content to "yes", using the UpdateRecord method you must use a map as parameter.

B4X:
Dim mapFieldsToUpdate As Map
mapFieldsToUpdate.Initialize
mapFieldsToUpdate.Put("FieldName1", "Value1")
mapFieldsToUpdate.Put("FieldName2", "Value2")
mapFieldsToUpdate.Put("fav", "yes")
mapFieldsToUpdate.Put("FieldName3", 3)

DBUtils.UpdateRecord(sql1, "table2", mapFieldsToUpdate, WhereFieldEquals)


(I assumed that this code is correct:
B4X:
Dim recno As Int
recno=dbcursor.GetInt("slno")
)
 

klaus

Expert
Licensed User
Longtime User
@LucasMS
you are confusing UpdateRecord with UpdateRecord2.
In UpdateRecord Field is the column name as a String.
In UpdateRecord2 Fields is a Map.

@mkvidyashankar
For me your code should work.
Is the column name OK ?
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…