I like to use the query method instead of rawQuery because it is more elegant for me, but it seems that the method can receive only one table as an input parameter.
Is there a solution for many tables?
I dont think there's any other method which can offer you this flexibility. Thats why the API comes with the method rawQuery(). Use sql query using UNION to join data from two tables.
for example:
String query = "SELECT Id, Name FROM Finance " +
"UNION ALL " +
"SELECT Id, Name FROM Marketing";
Cursor c = db.rawQuery(query, null);
Best will be just using rawquery, but if you must stick with query:
( please note, I have not tested this, but I imagine it will work )
You should be able to create a view ( http://sqlite.org/lang_createview.html ) and then use the view name in place of a table name.
Related
I have a table for orders and customers. Customers contains an order ID and email. I wish to search for orders by customer email.
This is what I have come up with:
#RewriteQueriesToDropUnusedColumns
#Query(
"SELECT * FROM orders INNER JOIN order_customers ON order_customers.order_id = orders.id " +
"WHERE (order_customers.email LIKE '%' || :email || '%') ORDER BY orders.collection_time DESC"
)
protected abstract fun loadByEmail(email: String): LiveData<List<Order>>
I get a cursor mismatch warning "the query returns some columns which are not used" that I am loading all of the customer columns, when really all I want is orders. Adding the suggested #RewriteQueriesToDropUnusedColumns does not do anything. So what is the best syntax here? Should I just be embedding customers into the order DAO, or is there a simple solution without remodeling and migrating the data?
I can see that instead of saying SELECT * I can individually specify every order column but that is supposed to be the whole reason for Room...
You can use SELECT orders.* FROM orders INNER JOIN ....
Adding the suggested #RewriteQueriesToDropUnusedColumns does not do anything.
This could be because of the caveat:-
Note that Room will not rewrite the query if it has multiple columns that have the same name as it does not yet have a way to distinguish which one is necessary.
I'd suggest always using unique column names, doing so can avoid issues with ambiguities
Note that it appears that when there are duplicate column names, then the value of last column with the duplicated name is used by room. As can be seen in this example
I am just porting some JDBC code (intended for use with HSQLDB) to Android’s own SQLite implementation. I have a snippet where I delete records based on a particular field matching one of the values in a String[] array in my Java code.
Here is the JDBC code for the DELETE statement:
String[] ids = getIdsSomehow();
PreparedStatement stmtD = db.prepareStatement("delete from message where id in (unnest(?))");
Array delIdArray = stmtD.getConnection().createArrayOf("VARCHAR", ids);
stmtD.setArray(1, delIdArray);
stmtD.execute();
stmtD.close();
Another snippet does a SELECT instead of DELETE and has the values in a List<String> instead of an array.
How would I accomplish this with the methods offered by SQLiteDatabase, preferably in a way that does not open up any SQL injection vulnerabilities?
The main “ingredients” to make this work with HSQLDB over JDBC, namely the unnest() function of the DBMS, and the ability to pass array values to SQL statements, are not available with the android.sqlite stack, making a workaround necessary:
String[] ids = getIdsSomehow();
String whereClause = "id in (" + TextUtils.join(",", Collections.nCopies(ids.size(), "?")) + ")";
db.delete("message", whereClause, ids);
This builds a where clause à la id in (?,?,?,?) with the correct number of question marks.
For the selection, use rawQuery() with a SELECT statement built in the same manner. The List<String> can be converted to an array like this:
ids.toArray(new String[]{})
Input came from this answer and its comments.
I am struggling to get more complicated queries to work with SimpleCursorAdapter and ViewBinder with a ListView. When I was just returning all entries in my table, that was no problem. However, I want to return a list of artist names from my tables in order of name. The big problem concerns the "rowid _id" field which SimplerCursorAdapter/ViewBinder expects.
My code worked fine when I had queries of the form SELECT rowid _id, Artist.NAME etc, but I want to use the DISTINCT keyword to return the unique set if artist names. I can't put "rowid _id" before "DISTINCT Artist.Name" and I can't put it after. What is the solution for this?
The query I want (A) is (shown without the "rowid _id"):
String sQuery = String.format( "SELECT DISTINCT Artist.Name, Artist.ID FROM Artist JOIN Tune ON Artist.ID=Tune.ArtistID AND Tune.Type=%d AND Tune.SubType=%d ORDER BY Artist.Name", nType, nSubtype );
To clarify, this works:
Cursor c = db.rawQuery( "SELECT rowid _id, Name, Rating FROM Tune ORDER BY Name", null );
Whenever I put rowid _id back into query (A), I get "no such column rowid" exceptions:
String sQuery = String.format( "SELECT rowid _id, Artist.Name, Artist.ID FROM Artist JOIN Tune ON Artist.ID=Tune.ArtistID AND Tune.Type=%d AND Tune.SubType=%d ORDER BY Artist.Name", nType, nSubtype );
What am I doing wrong?
EDIT: I don't even understand what the "rowid _id" does anyway - my SQLite Manager (test tool) doesn't like it either when I have a query with a join. It only seems to work on a simple 1 table query.. So if thats the case.. how do I make this query work without it for SimpleCursorAdapter & ViewBinder?
The answer was to forget about using rowid and use my own Artist.ID field instead. This will work as long as I alias the field name to _id which SimpleCursorAdapter expects in column 0.
String sQuery = String.format( "SELECT DISTINCT Artist.ID _id, Artist.Name FROM Artist JOIN Tune ON Artist.ID=Tune.ArtistID AND Tune.Type=%d AND Tune.SubType=%d ORDER BY Artist.Name", nType, nSubtype );
I am building an Android app that uses a SQLite database.
For this one task I have to run a query that looks like this:
SELECT item.id, item.price, t1.quantity
FROM item, (SELECT id, price
FROM list
WHERE list.state = 'sold') t1
WHERE item.id = t1.id
So far, I have tried:
Cursor c = resolver.query(uriRawQuery, null, selection, null, null)
where uriRawQuery is used to tell the ContentProvider that it should perform a db.rawQuery(selection, null) and selection is a string similar to the query above.
The problem is no data is returned into the Cursor. When I call c.moveToFirst() I get false.
The weird thing is that if I open the database file in SQLite Manager and run the exact same query I get results.
I know I can modify the query to make a join between the original list and item tables but I find it to be less efficient that way.
Any ideas would be very appreciated as I have spent too man hours on this already.
EDIT
I know what a join is, what I said is that it is a lot more efficient if I do it like this instead of using the entire list table.
I forgot a very important aspect
The WHERE clause looks like
" WHERE list.state = 'sold' and list.name like '" + arg + "%'"
where arg is a string.
I managed to solve the problem, I still don't know why this was happening but at least I got the Cursor to actually select the rows.
After many trials I thought about ditching the syntax above and write this instead:
" WHERE list.state = 'sold' and list.name like ? "
and move the argument in
selectionArgs = new String[]{arg + "%"}
I am going to wait a while before accepting the answer, in case someone provides an explanation as to why even though both queries look exactly the same they get different results.
I have 2 tables A and B.
Table A contains names and table B contains selected names.
Now I would like to perform the following query on these tables using greendao, Please let me know if it is possible and if it is not are there any alternatives (maybe a raw query).
select *
from A inner join B
on A.nameid = B.nameid
Also, Table A columns: id, nameid, name
and Table B columns: id, nameid, name, rating
I think this might help.
You can use the raw query as a fake join. And you get all you want in the Query object
Query query = ATableDao.queryBuilder().where(
new StringCondition("nameid IN " +
"(SELECT nameid FROM B_Table )").build();
Since "nameid" doesn't seems to be a unique identifier in your sample. I won't suggest to use Relations to solve this issue. If you are try to use Relations, you can find my previous answer here.
Try this:
List<ATableObj> listATableObj = ATableDao.queryRawCreate(", BTable BT
WHERE BT.nameid = T.nameid").list();
If you use greendao this works differntly:
Instead of your query you select rows from table a (or b) and if you need a field of b (or a) you call getB() (or getA()) to get the corresponding row of that table.
If you have rows in table a that have no match in table b and you have rows in table b that have no match in a and you onlly want to select everything that has matches uin both tables, you would have to do a raw query to filter the rows of a (or b).