I have a query that joins 2 tables get the required data on my android, what picture here is the user clicks on an item and the item's ID is used to query the right data in the Database, I know I can simply use database.query() but it according to my research it is used for simply database querying only, in my case I should use rawQuery() which provides more power of the database. below is my query which links table 1 to table 2 to get the users name from table one and user last name from table 2 if the foreign key is the same as user key
Assume this is my query:
String sQuery = SELECT table1.ID, table2.userlastname FROM table1, table2 WHERE "+table1.ID = table2.foreign;
If i try to specify the user id like below it gets all data in the database table which means i should replace id with "=?" but how do I do this when I am dealing which such a query, one that uses db.rawQuery() instead of db.query()
`private Object userInfo(int id)
{
String sQuery = SELECT table1.ID, table2.userlastname
FROM table1, table2 WHERE "+table1.ID = id;
}`
Basically you replace the parameter by question marks '?' and pass them through a String array in the order they appear in the query.
String queryStr = "SELECT table1.ID, table2.userlastname
FROM table1
INNER JOIN table2 ON table1.ID = table2.foreign;
WHERE table1.ID = ?";
String[] args = new String[1];
args[0] = String.valueOf(id);
Cursor cur = db.rawQuery(queryStr, args);
it did not work until I joined table 2 like:
`String queryStr = "SELECT table1.ID, table2.userlastname
FROM table1
INNER JOIN table2 ON table1.ID = table2.foreign
WHERE table1.ID = ?";
String[] args = new String[1];
args[0] = String.valueOf(id);
Cursor cur = db.rawQuery(queryStr, args);`
I have two tables atm, users and notes. I am trying to retrieve data that belongs to the user. So all data to list must be owned by the original user and shown only to him. I have made my table in Databasehelper.
I have made a new class that controls the notes table. In listNotes() I want to loop through the cursor row and get all data owned by the user. Am I quering it correctly?
// Listing all notes
public Cursor listNotes() {
Cursor c = db.query(help.NOTE_TABLE, new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
db.close();
return c;
}
I then want to display the cursor data collected in a listview
public void populateList(){
Cursor cursor = control.listNotes();
getActivity().startManagingCursor(cursor);
//Mapping the fields cursor to text views
String[] fields = new String[]{help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE};
int [] text = new int[] {R.id.item_title,R.id.item_body, R.id.item_date};
adapter = new SimpleCursorAdapter(getActivity(),R.layout.list_layout,cursor, fields, text,0);
//Calling list object instance
listView = (ListView) getView().findViewById(android.R.id.list);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}
You aren't creating the NOTE_TABLE right.
You miss a space and a comma here
+ COLUMN_DATE + "DATETIME DEFAULT CURRENT_TIMESTAMP"
It has to be
+ COLUMN_DATE + " DATETIME DEFAULT CURRENT_TIMESTAMP,"
There are two issues here:
One is you have missed a comma (after the Timestamp as specified in an earlier answer).
The other error you have is when using a SimpleCursorAdapter, you need to ensure that the Projection string array includes something to index the rows uniquely and this must be an integer column named as "_id". SQLite already has a feature built in for this and provides a column named "_id" for this purpose (however you can have your own integer column which you can rename to _id). To solve this, change your projection string array to something like:
new String[] {"ROW_ID AS _id", help.COLUMN_TITLE,help.COLUMN_BODY, help.COLUMN_DATE}
I guess the NullPointerException stems from this (but without the stacktrace I don't know for sure).
I am using INNER JOIN on two tables,table1 and table2, from my SQLite Database.
How do I access the results(columns of both tables) from the cursor? The two tables have 2 columns with same name.
String query = SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id WHERE name like '%c%';
Cursor c = newDB.rawQuery(query, null);
You can specify column names instead of using '*'.
String query = SELECT table1.id AS ID,table2.column2 AS c2,...... FROM table1 INNER JOIN table2 ON table1.id=table2.id WHERE name like '%c%';
and then access using column name ID,c2 etc .
while (cursor.moveToNext()) {
String c2 = cursor.getString(cursor.getColumnIndex("c2"));
int id = cursor.getInt(cursor.getColumnIndex("ID"));
..............
.............
}
Editing the broken link : Check rawQuery methid here http://www.vogella.com/tutorials/AndroidSQLite/article.html
and here http://www.codota.com/android/methods/android.database.sqlite.SQLiteDatabase/rawQuery for different examples
You can access the result as you would with any other query.
The only difference is that there is a chance to name conflicts, same column name on both tables. In order to solve those conflict you would need to use the table name as a prefix.
For example
Long id = c.getLong(c.getColumnIndex(tableName1 + "." + idColumnName));
If this approach doesn't work. You should write your query as follows:
String query = SELECT table1.id AS table1_id FROM table1 INNER JOIN table2 ON table1.id=table2.id WHERE name like '%c%';
Cursor c = newDB.rawQuery(query, null);
And another general note, it is better not to use "Select *..." it is preferred to write explicitly which column you would like to select.
Cursor c=databseobject.functionname() //where query is used
if(c.movetofirst()) {
do {
c.getString(columnindex);
} while(c.movetoNext());
}
I have used the following to do an inner join:
public Cursor innerJoin(Long tablebId) {
String query = SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id WHERE name like '%c%';
return database.rawQuery(query, null);
}
You can Iterate your cursor as below:
Cursor cursor = innerJoin(tablebId);
String result = "";
int index_CONTENT = cursor.getColumnIndex(KEY_CONTENT);
cursor.moveToFirst();
do{
result = result + cursor.getString(index_CONTENT) + "\n";
}while(cursor.moveToNext());
Hope this works for you
If you know the column name then you can find it like below,
long id = cursor.getLong(cursor.getColumnIndex("_id"));
String title = cursor.getString(cursor.getColumnIndex("title"));
if you just want to see all the columns name of the returned cursor then you can use String[] getColumnNames() method to retrieve all the column names.
Hope this will give you some hint.
I've got the following cursor set up to fill a dialog box with a users payment history
Cursor PaymentsCursor = db.getReadableDatabase().rawQuery(
"SELECT _id, Date, Payment FROM tblPaymentHistory WHERE DebtName = '"
+ debtname + "'" + "ORDER BY _id ASC", null);
SimpleCursorAdapter HistoryAdapter = new SimpleCursorAdapter(this,
R.layout.paymenthistoryrow, PaymentsCursor, from, to);
The problem is though that if there is more than one type of debt, and payments are made to each debt out of order, when the payment history returns it's results, it returns as out-of-order row numbers, for example 1,2,6,7,9,12,etc. I know it's pulling the _id (unique key) from the database, but is there a way to re-base or change the row number in the query, so that each result returns as "1,2,3,4,5,etc" regardless of original ID?
I thought that the ORDER BY _id or even ORDER BY Date ASC would fix this but it didn't.
My rows in the database look something like this:
1, TEST, 4/13/2012, 250
2, TEST, 4/13/2012, 300
3, TEST, 4/14/2012, 222
4, TEST2, 4/14/2012, 500
5, TEST, 4/15/2012, 600
When the user clicks history for "TEST", it returns back as 1,2,3,5... and if they pull up history for "TEST2", it shows as "4", I'm trying to get it so TEST shows "1,2,3,4" and TEST2 shows "1"
Damn I can't answer my own answer, but here's what I ended up doing:
Thanks guys. I found an alternate option that modified the view, so as not having to touch the SqLite db. heres the link that i foundModifying SimpleCursorAdapter's data
And here is the result:
PaymentsCursor = db.getReadableDatabase().rawQuery(
" SELECT _id, Date, Payment FROM tblPaymentHistory WHERE DebtName = '"
+ debtname + "'" + "ORDER BY _id ASC", null);
String[] from = new String[] { DbAdapter.KEY_HISTORY_ID,
DbAdapter.HISTORY_DATE, DbAdapter.HISTORY_PAYMENT };
int[] to = new int[] { R.id.PAYMENTNO, R.id.PAYMENTDATE,
R.id.PAYMENTAMOUNT };
SimpleCursorAdapter HistoryAdapter = new SimpleCursorAdapter(this,
R.layout.paymenthistoryrow, PaymentsCursor, from, to);
HistoryAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int column) {
if (column == 0) { // let's suppose that the column 0 is the
// date
TextView tv = (TextView) view;
String rownum = String.valueOf(cursor.getPosition() + 1);
// here you use SimpleDateFormat to bla blah blah
tv.setText(rownum);
return true;
}
return false;
}
});
paymenthistory.setAdapter(HistoryAdapter);
It may not be the most glamourous way, but now each time the window comes up with the history, it's using the row number (plus one) to indicate which # it is.
Thanks all!
Here is one way to get the "re-based" ids. In this example, the "new ids" are based on the grade (i.e. the "old ids" in your case):
.headers on
create table foo (name text, grade int);
insert into foo values ('Joe', 45);
insert into foo values ('Anna', 98);
insert into foo values ('Julie', 78);
select name,
grade,
(select count(*) from foo t1 where t1.grade>=t2.grade) as rank
from foo t2;
select name,
grade,
(select count(*) from foo t1 where t1.grade>=t2.grade) as rank
from foo t2
order by rank;
Having saved this as foo.sql, I get this:
[someone#somewhere tmp]$ sqlite3 < foo.sql
name|grade|rank
Joe|45|3
Anna|98|1
Julie|78|2
name|grade|rank
Anna|98|1
Julie|78|2
Joe|45|3
I've played a bit with what #sixfeetsix answered and since that fails to give 1,2,3,4,.. numbering in combination with the WHERE you might need to put in more subqueries (maybe not but, I'm not that good with queries):
SELECT (
SELECT count( * ) + 1
FROM (
SELECT *
FROM tblPaymentHistory
WHERE DebtName = ?
)
AS t1
WHERE t1._id < t2._id
)
AS _id,
Date,
Payment
FROM tblPaymentHistory AS t2
WHERE DebtName = ?
ORDER BY _id;
put in java String and leave the ? in there to get escaped values (injection safe):
Cursor PaymentsCursor = db.getReadableDatabase().rawQuery(
"...WHERE DebtName=? .. WHERE DebtName=? .. ", new String[]{ debtname, debtname });
SimpleCursorAdapter HistoryAdapter = new SimpleCursorAdapter(this,
R.layout.paymenthistoryrow, PaymentsCursor, from, to);
This query worked for me after long research...
Empirical results I derived :
1)You need to define where condition in sub-query also.
2)if ids (t2._id <= t1._id) compared in relation operator will be primary keys then it
will work fine in all cases.
3)Regarding orderby condition you have to decide that according to your choice or need.
SELECT
(SELECT COUNT(*) FROM table t2 WHERE t2._id <= t1._id AND t2.Recipe_id = 2) AS RowNumber,_id,Recipe_id,col2,col3,col4
FROM table t1
WHERE Recipe_id = 2
ORDER BY _id
How it works:-
Say we have a sequence of primary keys 1,2,3,4,5,6 in some table t
Now we create two aliases of it using table t1 and table t2
Now both have same sequence table t1 -> 11,12,13,14,15,16
table t2 -> 11,12,13,14,15,16
now this condition ( WHERE t2._id <= t1._id ) compares first primary key "11" of t2 with
the first primary key "11" of t2 as 11=11 it will return count() that only one row exists, hence we get "1" in row number..
*** remember for every row in Outer query the sub-query is executed ***
Hence now outer query is at row second having primary key "12"
now it will again compare the ( WHERE t2._id <= t1._id ) this time again t2._id contains "11" while t1._id contains "12"..
Quiet clear it will return that TWO rows are there which are having ids <= 12 that is 11 and 12
this way it will generate the desired sequence.........
This is a simple trick to generate the sequence.. not simple actually in one look but really simple when you get into depth of it..
I am not expert but this is what i understood..
Hope the explanation helps...
As there are various solutions or same solutions available on net but no explanation..
:)
From my main.java:
Cursor c = db.getDue();
String[] columns = new String[] { "_id", "date" };
int[] to = new int[] { R.id.num, R.id.date };
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.lventer, c, columns, to);
ListView lv1 = (ListView)findViewById(R.id.ListView01);
lv1.setAdapter(mAdapter);
From my database wrapper class:
public Cursor getDue() {
//String getdue = "SELECT * FROM tb1"; // this returns _id+date and displays them in the listview via the cursor adapter, defined above
String getdue = "SELECT _id, max(date) AS date FROM tb1 GROUP BY _id";// this only works if I remove the "date" bindings defined above, only letting me see the _id, i want to see both _id and date in the lit view.
return db.rawQuery(getdue,null);
If I use the second select statment then it crashes unless I remove the "date" from the cursor adapter/listview bindings, if I do this then It will show the returned _id in the listview, but I want to see both _id and date in the listview.
I have been told that the second statment might returns a different type for date because of the max function ( I am not very sql literate, yet), but I thought that sqlite was loose with datatypes? Can anybody help, thanks in advance.
** UPDATE** This is the command that wont work with 2 columns fr the list view:
SELECT _id, max(date) FROM jobs GROUP BY _id HAVING max(date) < (date-21)
Use this:
String getdue = "SELECT _id, max(date) AS date FROM tb1 GROUP BY _id";