I'm trying to pass a string from Mainactivity to the databaseadapter class to update the column one with a string (as its designated with string instead of int) in sqlite but realize that db.update() only works with int.
a) In mainactivity, for int
Integer jacky = 78;
myDb.updateK(jacky);
b) In mainactivity, for String
String jackie = "jacko";
myDb.updateK(jackie);
In databaseadapter
String cup = "_id = 1";
//since jack doesn't have to be jacky or jackie, and can be mary
public void updateK(int mary){
ContentValues tree = new ContentValues();
tree.put("columnone", mary);
db.update("TableOne", tree, cup, null);
}
In the case above, only case a) works when using an int whereas case b) using a string jacko, does not work. Is there a way to work around this and pass the string from mainactivity to databaseadapter?
As you probably can tell, I'm new to android and I appreciate any pointers you guys can give me.
a) In mainactivity, for int
Integer jacky = 78;
myDb.updateK(jacky);
b) In mainactivity, for String
String jackie = "jacko";
myDb.updateK(jackie);
In databaseadapter
String cup = "_id = 1";
//since jack doesn't have to be jacky or jackie, and can be mary
public void updateK(Object mary){
ContentValues tree = new ContentValues();
tree.put("columnone", mary);
db.update("TableOne", tree, cup, null);
}
NOTE : Your tree should also accept objects
"columnone" should be a column name of table "TableOne". Verify the type of that column (you should define column data type when define your table). According to your question it should be a INTEGER type. If so you can change its type to TEXT then you have to change the case a) as follows.
myDb.updateK(String.valueof(jacky));
Related
I have a database in an android app and the following are its columns:
public class DBhelper extends SQLiteOpenHelper {
public static final String COL_TIPO = "ColonnaTipo";
public static final String COL_DIFFICOLTA="ColonnaDifficolta";
public static final String COL_INGREDIENTI = "ColonnaIngredienti";
//code
}
I use this function to make a query on it (TAB is the name of the table):
public Cursor query_filtri(String[] param, String[] p2) {
String whereClause="";
String[] whereArgs=new String[50];
whereClause=COL_TIPO+"=? AND "+COL_DIFFICOLTA+"=?";
whereArgs=new String[] {param[0],param[1]};
return getWritableDatabase().query(TAB,null,whereClause,whereArgs,null,null,null);
}
In param[] there are the values of COL_TIPO and COL_DIFFICOLTA that i am searching, and it works.
In p2[] there are 2 strings: p2[0] = "hi", p2[1]= "try".
I would modify the query to obtain the colums that in COL_INGREDIENTI contains the worlds hi and try.
For example:
I would try to obtain this
COL_INGREDIENTI "hi, would you try?"
and not this
COL_INGREDIENTI "hi, how are you?"
How can i modify the query? Is there a way to make it not case-sensitive?
You can add:
AND COL_INGREDIENTI like '%hi%' and COL_INGREDIENTI like '%try%'
From the documentation:
The LIKE operator is case sensitive by default for unicode characters that are beyond the ASCII range. For example, the expression 'a' LIKE 'A' is TRUE but 'æ' LIKE 'Æ' is FALSE
So, if you are using characters inside de ASCII range you don't need to worry about the case
I'm creating my first data enabled app but am struggling with the last part - actually adding and retrieving the data. For now I am only concerned with adding data to the table. Following this tutorial I have created model classes for my tables and a DBHelper class with all my CRUD methods (I can post all these if required but not sure they are necessary to answer this question. Please correct me if I am wrong!). Unfortunately the tutorial ends here and doesn't go into detail on how to pass the data from the UI of the app into the DB.
After some Google searches I have found an example of how to pass some data to these methods but only how to pass one piece of data at a time, so only really useful if my table has just one field - mine has more than one.
For example, if I have a a table for "Todo" tasks, in my dbhelper my create method may be;
public void createTodo(String todoText) {
ContentValues contentValues = new ContentValues();
contentValues.put("todo", todoText);
// Insert into DB
db.insert("todos", null, contentValues);
}
so from my activity I just need
dao.createTodo(todoTextValue);
For my app I will be adding more than one field at a time, so my create method looks like this;
public long createSite(Site site){
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_SITE_NAME, site.getSiteName());
values.put(KEY_SITE_LAT, site.getSiteLat());
values.put(KEY_SITE_LON, site.getSiteLon());
values.put(KEY_CREATED_AT, site.getSiteCreatedDateTime());
// Insert Row
long siteid = database.insert(TABLE_SITES, null, values);
So my question really is how I can pass all the different bits of data to the createSite method.
I don't know if this really needs an answer, but well here's a code...
Assuming your Site class is like this.
public class Site {
private String siteName;
private double siteLat;
private double siteLon;
private Date siteCreatedDateTime;
// getters and setters here
}
You then pass the data from your EditText value to your new Site object. It will look like this in your activity.
EditText siteNameInput = (EditText) findViewById(R.id.siteNameInput);
EditText siteLatInput = (EditText) findViewById(R.id.siteLatInput);
EditText siteLonInput = (EditText) findViewById(R.id.siteLonInput);
EditText siteCreatedDateTimeInput = (EditText) findViewById(R.id.siteCreatedDateTimeInput);
String siteName = siteNameInput.getText().toString();
String siteLat = siteLatInput.getText().toString();
String siteLon = siteLonInput.getText().toString();
String siteCreatedDateTime= siteCreatedDateTimeInput.getText().toString();
Site site = new Site();
site.setSiteName(siteName);
site.setSiteLat(siteLat);
site.setSiteLon(siteLon);
site.setSiteCreatedDateTime(siteCreatedDateTime);
dao.createSite(site);
Hope this helps you... You can learn more on Object-Oriented programming in Java here
public long createSite(Model site,String name, String address){
SQLiteDatabase database = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, site.name);
values.put(KEY_ADDRESS, site.address);
// Insert Row
long siteid = database.insert(TABLE_SITES, null, values);
to add elements to the class you just add
public class Model {
String name;
String address;
//add year as many as you need
Model(String name, String address){
this.name=name;
this.address=address;
}
}
And in you activity you call this
In java to add a new object in this case Model
Model x = new Model("josh","Ireland");
and you just pass to
dao.createTodo(x);
Todo and Site are models. Each variable represents a column of that table. You need to create a custom model for each of your tables. The createSite method takes an object of type Site and adds it as a row in the TABLE_SITES in the DB. values.put(...)takes columnName, value. So here you give your own column names and values.
Instead of getting into all this I suggest you use an orm like active android:
http://www.activeandroid.com/
With Active Android, can I get the column names of a table as a String[]?
RawQuery() returns a List<Model> so I can't just plug PRAGMA into it.
The suggested duplicate is about getting table names, and not related to Active Android.
Use these methods to get a collection of Fields:
public static synchronized TableInfo Cache.getTableInfo(Class<? extends Model> type);
public Collection<Field> TableInfo.getFields();
Then use public String TableInfo.getColumnName(Field field) on each Field to get column names. Example:
TableInfo<> userInfo = Cache.getTableInfo(User.class);
Collection<Field> fields = userInfo.getFields();
Set<String> columnNames = new HashSet<>();
for (Filed field : fields) {
String name = userInfo.getColumnName(field);
columnNames.add(name);
}
If you need to get id column name, use:
public String TableInfo.getIdName();
Ok after searching some more I found out I will need to deal with a Cursor, and I can get that by using Cache.
Like this:
Cursor c = Cache.openDatabase().rawQuery(new Select().from(User.class).toSql(),null);
String[] col = c.getColumnNames();
I wanted to search the database table for the row with an int value, not a string value, but when do this I get an error. So I wish I could do this however it is not possible:
updateRow(int titleCode, int questionCode, int inspectionResult){
So instead I am stuck with this,
updateRow(String titleCode, String questionCode, int inspectionResult){
How can I use the selection args like this;
new String[]{titleCode, questionCode}
to search for titleCode and questionCode if these variables are int/integer and not Strings?
as the fact that I cannot change the selection args array from a String type to an int type yet I want to search for int values in the database table
public void updateRow(String titleCode, String questionCode, int inspectionResult){
ContentValues contentValues = new ContentValues();
String selection = "INSPECTION_PLACE_CODE = ? AND INSPECTION_ITEM_CODE = ?";
contentValues.put(INSPECTION_RESULT_JUDGEMENT, inspectionResult);
sqLiteDatabase.update(DETAILS_TRAN_SMALL_INSPECTION_RESULTS, contentValues, selection,
new String[]{titleCode, questionCode});
}
https://www.sqlite.org/datatype3.html
Based on section 3.3, comparisons, including equality checks are subject to type affinity. You can safely test int values as Strings in SQLite because the database driver will auto convert your String to an int before comparing.
I am testing the capabilities of the device -- to show the customer the size of data that can be stored inside the device, how fast it can be retrieved, how fast the search works, etc.
I am using my content provider to access the product database table with few columns. I have already moved the code to the content provider to avoid the extra communication when inserting the test records. The following code is called via menu from an activity to fill the table with the test content
Uri uri = Uri.parse(DemoContentProvider.PRODUCTS_CONTENT_URI + "/insertdemo");
getContentResolver().insert(uri, null);
The URI is recognized in the .insert method of the content provider and the following private method (of the same content provider) is called to fill the table (notice the 100 thousands of items):
private void insertDemoProducts() {
for (int i = 1; i <= 100000; ++i) {
String id = Integer.toString(i);
insertProduct(id, "Test product " + id, "100", "75.50", "70.27");
}
}
The inner insertProduct() looks like that:
private void insertProduct(String code, String name, String stock,
String price, String listprice) {
SQLiteDatabase sqlDB = database.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ProductTable.COLUMN_CODE, code);
values.put(ProductTable.COLUMN_NAME, name);
values.put(ProductTable.COLUMN_STOCK, stock);
values.put(ProductTable.COLUMN_PRICE, price);
values.put(ProductTable.COLUMN_LISTPRICE, listprice);
sqlDB.insert(ProductTable.TABLE_PRODUCT, null, values);
}
It works, but it takes "forever". How can I make it faster? What is the fastest method you know to fill the table?
Just some numbers to consider: 1000 items takes about 20 seconds to be created.
You need to use transactions when writing to a sqlite-database, otherwise it will persist the data for every insert i.e save it to sd which will take "forever".
for instance, make insertProduct take a list of products and save them in one transaction:
private void insertProducts(List<Product> products) {
try {
db.beginTransaction();
for(Product product : products) {
insertProduct(...);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
This is how you can implement it in your existing code:
private void insertDemoProducts() {
SQLiteDatabase sqlDB = database.getWritableDatabase();
try {
sqlDB.beginTransaction();
for (int i = 1; i <= 100000; ++i) {
String id = Integer.toString(i);
insertProduct(id, "Test product " + id, "100", "75.50", "70.27");
}
sqlDB.setTransactionSuccessful();
} finally {
sqlDB.endTransaction();
}
}
Anyway, I am not completely satisfied with the accepted question because I do not understand the reason why adding the transaction makes it faster.
Looking at the Android sources, I have found that the sqlDB.insert(...) calls insertWithOnConflict(...) and that one construct the string for the SQL command using the StringBuilder class (with questionmarks as placeholders for the inserted values). Only then the string is passed to the SQLiteStatement constructor together with array of the inserted values. This means that string with the SQL command is being built again and again.
Further, a string representation of an SQL command template can be precompiled thus avoiding also the repeated compilation of the command. Then .bindXxx and .execute methods can be used for inserting the wanted records into the table. When put together, I did use the followig code (iside the outer transaction as Dean suggested):
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO ");
sql.append(ProductTable.TABLENAME);
sql.append("(");
sql.append(ProductTable.COLUMN_CODE);
sql.append(",");
sql.append(ProductTable.COLUMN_NAME);
sql.append(",");
sql.append(ProductTable.COLUMN_STOCK);
sql.append(",");
sql.append(ProductTable.COLUMN_PRICE);
sql.append(",");
sql.append(ProductTable.COLUMN_LISTPRICE);
sql.append(") VALUES (?, ?, 100, 75.50, 70.27)");
SQLiteStatement insert = sqldb.compileStatement(sql.toString());
for (int i = 1; i <= 300000; ++i) {
insert.bindLong(1, i);
insert.bindString(2, "Test product " + i);
insert.execute();
}
When compared with adding the transaction only, the result is about 3-times faster. The 300 thousands records were inserted in about 3 minutes and 15 seconds on Nexus 7.