I need to get data from two tables in Android. I am using OrmLite for the database.
My query is next:
SELECT m.*, r.campaign_name, r.description, r.terms_condition
FROM mycampaignlist m, redeemlanguagedata r
WHERE r.lang_type = 2
How could I create this type of query in OrmLite.
I need to get data from two tables in Android... How could I create this type of query in OrmLite.
ORMLite does not support JOIN queries using the internal QueryBuilder if you are selecting a combination of fields from each table. In your example, you have some fields from mycampaignlist and some from redeemlanguagedata so ORMLite can't return a object without more help.
I'd recommend using the raw queries functionality and then you can get the output as a List<String[]>, List<Object[]> if you specify the data-types, or as a list of your own objects if you specify a RawRowMapper<Foo>.
For example, to quote from the docs:
GenericRawResults<Foo> rawResults = orderDao.queryRaw(
"SELECT account_id,sum(amount) FROM orders GROUP BY account_id",
new RawRowMapper<Foo>() {
public Foo mapRow(String[] columnNames,
String[] resultColumns) {
return new Foo(Long.parseLong(resultColumns[0]),
Integer.parseInt(resultColumns[1]));
}
});
// page through the results
for (Foo foo : rawResults) {
System.out.println("Account-id " + foo.accountId + " has "
+ foo.totalOrders + " total orders");
}
rawResults.close();
Hope this helps.
Related
Recently I got to know that raw query in android can not prevent SQL injection and thus I decided to convert all queries in Prepared statement which is SQL injection prevention. But I don't know how to convert complex queries in Prepared Statement.
I want to convert below queries:
1.
select
*
FROM
TableName
where
(tab1col1 in(SELECT tab2Col2 FROM MasterTable where tab2col1='Y')
or tab1col2 = CV.TRUE)
order by
tab1col3, tab1col4, tab1col5,tab1col6
2.
Select
* ,count(*) as TOTAL_COUNT ,
SUM(CASE WHEN tabCol1 LIKE '%todayDate%' THEN 1 ELSE 0 END) as TOTAL_COL1_COUNT
from
TableName
group by tabCol2;
You can use rawQuery to prevent injection by passing any arguments via the selectionargs (2nd parameter).
SQL injection, wouldn't apply to either of the queries, as they are hard coded and have no user generated/supplied inputs.
e.g. your first query could be (assuming that, 'Y' and CV.TRUE are passed as parameters (i.e. user generated/supplied) for the sake of demonstration) :-
public Cursor query1raw(String indicator1,String indicator2) {
String sql = "SELECT * " +
" FROM TableName " +
" WHERE (tab1col1" +
" IN(" +
" SELECT tab2col2 " +
" FROM MasterTable " +
" WHERE tab2col1=?)" +
" OR tab1col2=?)" +
" ORDER BY tab1col3, tab1col4,tab1col5,tab1col6";
String[] args = new String[]{indicator1,indicator2};
return mDB.rawQuery(sql,args);
}
However, the convenience methods are generally recommended rather than rawQuery or execSQL when they can be used, again using bound strings via arguments, the above, using the query convenience method could be :-
public Cursor query1(String indicator1, String indicator2) {
String whereclause = "(tab1col1 IN(SELECT tab2col2 FROM MasterTable WHERE tab2col1=?) OR tab1col2=?)";
String[] whereargs = new String[] {indicator1,indicator2};
String order_columns = "tab1col3,tab1col4,tab1col5,tab1col6";
return mDB.query("TableName",null,whereclause,whereargs,null,null,order_columns);
}
You wouldn't use prepared statements themselves as they are restricted to returning single values, not a row or rows with multiple columns.
Warning not advised
However, you could, if you really wanted, use :-
public Cursor query1ps(String indicator1,String indicator2) {
String[] whereargs = new String[] {indicator1,indicator2};
SQLiteStatement stmnt = mDB.compileStatement("SELECT * " +
" FROM TableName " +
" WHERE (tab1col1" +
" IN(" +
" SELECT tab2col2 " +
" FROM MasterTable " +
" WHERE tab2col1=?)" +
" OR tab1col2=?)" +
" ORDER BY tab1col3, tab1col4,tab1col5,tab1col6");
stmnt.bindAllArgsAsStrings(whereargs);
Log.d("PREPAREDSQL",stmnt.toString());
String sql = stmnt.toString().replace("SQLiteProgram:","");
return mDB.rawQuery(sql,null);
}
As you can see all the prepared statement is doing as such, is substituting the arguments, so has little benefit over the other methods. This would also be dependant upon SQLIteProgram: remaining constant.
The only way to prevent SQL injections is to use parameters. (In some PHP APIs, the only way to get parameters is to use prepared statements, but that is not one of the warts in the Android database API.)
Just write ? for any string, and pass the values separately:
String name = ...;
String password = ...;
cursor = db.rawQuery("SELECT SomeCol FROM Users WHERE Name = ? AND Password = ?",
new String[]{ name, password });
Please not that SQL injection could happen only if you have string values that are controlled by the (potentially-hostile) user. Your queries above do not look as if this were the case.
I have a hibernate query which selects particular data from two tables using its model class based on certain conditions. Now i want to convert that query to ORMLite query to use in my android application, but I didn't know how to do it using queryBuilder() in ORMLite because I am a beginner in ORMLite.
Query query = getCurrentSession().createQuery(
"SELECT A.accountID,A.name,B.allowTransactions from Payments A,Accounts B "
+ "WHERE A.accountID=B.id AND B.id NOT IN (5,55,602) AND A.active=1 AND "
+ "B.parentID=:pID AND B.date BETWEEN :sDate AND :eDate GROUP BY A.id "
+ "ORDER BY CASE WHEN A.name=:name THEN 1 ELSE 0 END,A.name");
query.setParameter("pID",4);
query.setParameter("name", "Others");
query.setParameter("sDate",startDate);
query.setParameter("eDate", endDate);
Below are the getter method for Payments and Accounts classes.
dbHelper.getPaymentDao() and dbHelper.getAccountDao()
I have a hibernate query which selects particular data from two tables using its model class based on certain conditions. Now i want to convert that query to ORMLite query...
This query is not supported by ORMLite's QueryBuilder given its complexity. You can certainly use the dao.queryRaw(...) method and then process the results yourself by hand.
GenericRawResults<String[]> results = paymentDao.queryRaw(
"SELECT A.accountID,A.name,B.allowTransactions from Payments A,Accounts B "
+ "WHERE A.accountID=B.id AND B.id NOT IN (5,55,602) AND A.active=1 AND "
+ "B.parentID=? AND B.date BETWEEN ? AND ? GROUP BY A.id "
+ "ORDER BY CASE WHEN A.name = ? THEN 1 ELSE 0 END,A.name",
parentId, fromDate, toDate, name);
Notice that I've converted the : args into ? arguments.
That returns String results but you can also use the other Dao.queryRaw(...) methods to properly convert the results into Java entities.
See: http://ormlite.com/docs/raw-queries
I'm making an Android app and using a SQLite database. In particular I'm using the rawQuery method on a database obtained through a SQLiteOpenHelper. The query I build makes use of the ? marks as placeholders for the real values, which are passed along as an array of objects (e.g., select * from table where id = ?).
The question is, is it possible to get the query with the marks already replaced, at least from the cursor returned from the rawQuery method? I mean something like select * from table where id = 56. This would be useful for debugging purposes.
It's not possible. The ? values are not bound at the SQL level but deeper, and there's no "result" SQL after binding the values.
Variable binding is a part of the sqlite3 C API, and the Android SQLite APIs just provide a thin wrapper on top. http://sqlite.org/c3ref/bind_blob.html
For debugging purposes you can log your SQL with the ?, and log the values of your bind arguments.
You could form it as a string like this
int id = 56;
String query = "select * from table where id = '" + id + "'";
and then use it as a rawQuery like this (if I understood your question properly)
Cursor mCursor = mDb.rawQuery(query, null);
You can also use the SQLiteQueryBuilder. Here is an example with a join query:
//Create new querybuilder
SQLiteQueryBuilder _QB = new SQLiteQueryBuilder();
//Specify books table and add join to categories table (use full_id for joining categories table)
_QB.setTables(BookColumns.TABLENAME +
" LEFT OUTER JOIN " + CategoryColumns.TABLENAME + " ON " +
BookColumns.CATEGORY + " = " + CategoryColumns.FULL_ID);
//Order by records by title
_OrderBy = BookColumns.BOOK_TITLE + " ASC";
//Open database connection
SQLiteDatabase _DB = fDatabaseHelper.getReadableDatabase();
//Get cursor
Cursor _Result = _QB.query(_DB, null, null, null, null, null, _OrderBy);
I've been looking on this site for a while but have not found the answer. I am trying to do a bulk update on data that I know is already in the table. I have one column that needs to be set when a certain condition comes back for the row ID. Here is the single method but I want to make this more efficient and do it as a bulk. Our database is not in a Provider so I just using a Helper class.
public void markUnavailable(int myId) {
SQLiteDatabase db = this.getWritableDatabase();
String sql = "UPDATE " + MYTABLE + " SET " + Col.IS_AVAILABLE + "= 0"+ " WHERE " + Col.MY_ID + "=" + myId;
db.execSQL(sql);
db.close();
}
I would like to pass in an array of myIds to do the bulk Update. I can't do a Insert or Replace statement because I don't have access to all the column data and don't want to pass this through due to too many codes changes.
public void markUnavailable(int[] myId) {
// ????
/// need some way to loop through and update in bulk
}
Try UPDATE tablename SET column=0 WHERE ID IN (...), where ... is a comma-delimited list of ID values.
I'm not an Android developer, but according to good database practices, you should:
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?";
for (int i = 0; i < myId.length; i++) {
upd.bindLong(1, myId[i]);
upd.execute();
}
db.endTransaction();
}
Android has SQLiteDatabase.update would be very usefull in this case, but String [] whereArgs would not deal well with your int[] myId.
The fastest way to do a bulk update would be to do it as a single transaction,by using begin and end transactions. Also if the size of the database is large it will be a good idea to make myID as the primary key of the table as it will significantly increase the speed of the speed in fetching the rows for update when the WHERE clause is used.[It is said that indexing can reduce the speed of update and insert but when the where clause is used,indexing has always increased my speed by huge margins.
public void markUnavailable(int[] myId) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
SQLiteStatement upd=db.compileStatement("UPDATE "+MYTABLE+" SET "+Col.IS_AVAILABLE+"=0 WHERE "+Col.MY_ID+"=?");
for (int i = 0; i < myId.length; i++) {
upd.clearBindings();
upd.bindLong(1, myId[i]); // this matches the first "?"
upd.execute();
}
db.setTransactionSucessful();
db.endTransaction();
}
I'm working on a conference application where we want the sessions to be first grouped by time and then by room location. I have successfully sorted by one or the other in my ExpandableListActivity, but have been unsuccessful with both the primary and secondary sort.
(source: coreylatislaw.com)
Set up
Custom content provider (extends ContentProvider)
Custom list adapter (extends BaseExpandableListAdapter)
Custom list activity (extends ExpandableListActivity)
Query
Cursor cursor = context.getContentResolver()
.query(uri,
ScheduleData.PROJECTION,
null,
null,
ScheduleData.SORT_ORDER);
Sort order
public static final String SORT_ORDER = TimeSlots.QUALIFIED_TIMESTART + " ASC"; // timeslots.timestart
Failed primary & secondary sort orders
public static final String SORT_ORDER = TimeSlots.QUALIFIED_TIMESTART + " ASC, " + Locations.QUALIFIED_NAME + " ASC"; // timeslots.timestart ASC, locations.name ASC
public static final String SORT_ORDER = TimeSlots.QUALIFIED_TIMESTART + ", " + Locations.QUALIFIED_NAME + " ASC"; // timeslots.timestart, locations.name ASC
The second clause seems to have no affect on the ordering. Is this a limitation of the ExpandableListActivity? Should I specify multiple sort order items differently?
Turns out that there was a comparator in the class that was overriding the sort order specified in the ORDERBY clause. When using the ORDERBY clauses above with out the comparator, I got the desired sorting. You can do it either way, but I'm killing the extra code and choosing the ORDERBY clause.
The comparator path:
// Sort children
Collections.sort(group.children, CHILD_COMPARATOR);
// Specify sort by location
static final Comparator<Child> CHILD_COMPARATOR = new Comparator<Child>()
{
#Override
public int compare (Child child1, Child child2)
{
return child1.location.toLowerCase().compareTo(child2.location.toLowerCase());
}
};
Just get the data into an 'ArrayAdapter', sort it the way you want and then set back the adapter to the activity list.
this is not really an answer, but i cant write comments yet.
The SORT_ORDER String should be correct.
But what you can try is to use the shell and execute the sql lite query directly so that you can narrow down the problem.
start up emulator with your app
in your console type :
adb shell
now navigate to the directory of your app; for example:
cd /data/data/com.myapp/databases)
start the SQLLite command line tool by typing:
sqlite3 < filename >
If you dont know the name of your database file simply type in "ls" do see all files in this directory.
you can now type in your query. For example:
SELECT * FROM timeslots,locations ORDER BY timeslots.timestart, locations.name;
reference:
http://www.sqlite.org/sqlite.html