I have a task in which i have to display the rows selected using a query in one tab and the remaining rows in another tab. I have displayed the selected rows using SimpleCursorAdapter. When i tried to display the remaining rows in next tab it throws error. I have tried NOT IN but it also doesn't work. I have tried NOT EXISTS also it shows all rows. Anyone who can answer please help. I have posted my code here. Thanks in advance.
This is the activity of first tab which displays selected rows
public class OnlineDevices extends Activity {
ListView listOnline;
DatabaseHelper databaseHelper;
String count;
int conut;
TextView tvOnlineCount;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_online_devices);
listOnline=(ListView)findViewById(R.id.listView3);
tvOnlineCount = (TextView) findViewById(R.id.textView59);
databaseHelper=new DatabaseHelper(this);
SQLiteDatabase db=databaseHelper.getReadableDatabase();
String date= DateFormat.getDateInstance().format(new Date());
String statusQuery="select rowid _id, deviceContact from statusTable where sentTime='"+date+"'";
Cursor cursor1=db.rawQuery(statusQuery,null);
if (cursor1.getCount()>0){
while (cursor1.moveToNext()){
String deviceNo=cursor1.getString(cursor1.getColumnIndex("deviceContact"));
String device=deviceNo.substring(2, 12);
String query="select rowid _id, userName, uSerialNo from bikeTable where uContactNo='"+device+"' AND userName IS NOT NULL";
Cursor cursor2=db.rawQuery(query, null);
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.status_item,cursor2,new String[]{"userName","uSerialNo"},new int[]{R.id.textView51,R.id.textView52});
listOnline.setAdapter(adapter);
}
}
try {
conut = listOnline.getAdapter().getCount();
count = String.valueOf(conut);
tvOnlineCount.setText(count);
}catch (Exception e){
e.printStackTrace();
int i=0;
Toast.makeText(OnlineDevices.this,"No device is active",Toast.LENGTH_SHORT).show();
tvOnlineCount.setText(String.valueOf(i));
}
}
}
Activity for second tab which display the remaining rows are
public class OfflineDevices extends Activity {
ListView listOffline;
DatabaseHelper databaseHelper;
String deviceContact;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_offline_devices);
listOffline=(ListView)findViewById(R.id.listView4);
databaseHelper=new DatabaseHelper(this);
SQLiteDatabase db=databaseHelper.getReadableDatabase();
String date= DateFormat.getDateInstance().format(new Date());
String query="select rowid _id, deviceContact from statusTable where sentTime='"+date+"'";
Cursor cursor1=db.rawQuery(query,null);
if (cursor1.getCount()>0){
while (cursor1.moveToNext()) {
deviceContact = cursor1.getString(cursor1.getColumnIndex("deviceContact"));
}
String device=deviceContact.substring(2, 12);
String query2="select rowid _id, userName, uSerialNo from bikeTable where userName IS NOT NULL AND uContactNo='"+device+"'";
Cursor cursor3=db.rawQuery(query2,null);
String query1="select rowid _id,*from bikeTable where userName IS NOT NULL NOT IN('"+query2+"')";
Cursor cursor2=db.rawQuery(query1,null);
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.status_item,cursor2,new String[]{"userName","uSerialNo"},new int[]{R.id.textView51,R.id.textView52});
listOffline.setAdapter(adapter);
}
}
}
You have syntax errors in your query. In theory the following should work:
String query2 = "SELECT userName FROM bikeTable WHERE userName IS NOT NULL "
+ "AND uContactNo = '" + device + "'";
String query1 = "SELECT * FROM bikeTable WHERE userName IS NOT NULL "
+ "AND userName NOT IN(" + query2 + ")";
Here are the differences:
Your original code has single quotes around query2 inside the parentheses. This makes SQLite treat it as a string literal instead of an inner query.
Since query2 is being used in a NOT IN expression, it needs to
have a single result column, and it seems like userName is the one
you are interested in.
I advise spending some time going through the SQLite language pages. I'm fairly certain you can actually get the results you want using a single query that has a JOIN instead of making one query, checking the result, then making another query.
As an aside, it's considered best practice in Android to load data from a database on a background thread. Typically this is done with the Loader framework. You should also be closing cursors when you are finished with them (not the ones you give to the adapters, but the ones you use just to check for an online device).
Related
I want to fetch phone number linked to particular email in the database. I am not able to find the query for it or how
public String getContactNumber(String email){
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT " + COLUMN_USER_MOBILE_NUMBER + " FROM " + TABLE_USER + " WHERE " + email + " = " + COLUMN_USER_EMAIL;
Cursor cursor = db.rawQuery(query,null);
//What to put here to extract the data.
String contact = cursor.getString(get);
cursor.close();
return contact;
}
to extract the data. Completely a beginner
Try this ..
public List<String> getMyItemsD(String emailData) {
List<String> stringList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT COLUMN_USER_MOBILE_NUMBER FROM " + USER_TABLE_NAME + " WHERE email= " + emailData;
Cursor c = db.rawQuery(selectQuery, null);
if (c != null) {
c.moveToFirst();
while (c.isAfterLast() == false) {
String name = (c.getString(c.getColumnIndex("Item_Name")));
stringList.add(name);
c.moveToNext();
}
}
return stringList;
}
public String getContactNumber(String email){
String contact = "";
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT " + COLUMN_USER_MOBILE_NUMBER + " FROM " + TABLE_USER + " WHERE " + email + " = " + COLUMN_USER_EMAIL;
Cursor cursor = db.rawQuery(query,null);
if(cursor.getCount()>0) {
cursor.moveToNext();
contact = cursor.getString(cursor.getColumnIndex(COLUMN_USER_MOBILE_NUMBER));
}
//What to put here to extract the data.
cursor.close();
return contact;
}
From this method you get phone number value of that email which you pass any other method easily.
I'd suggest the following :-
public String getContactNumber(String email){
String contact = "NO CONTACT FOUND"; //<<<<<<<<<< Default in case no row is found.
SQLiteDatabase db = this.getWritableDatabase(); //<<<<<<<<<< Generally getReadable gets a writable database
String[] columns_to_get = new String[]{COLUMN_USER_MOBILE_NUMBER};
String whereclause = COLUMN_USER_EMAIL + "=?";
String[] whereargs = new String[]{email};
Cursor cursor = db.query(TABLE_USER,columns_to_get,whereclause,whereargs,null,null,null);
//What to put here to extract the data.
if (cursor.moveToFirst()) {
contact = csr.getString(csr.getColumnIndex(COLUMN_USER_MOBILE_NUMBER));
}
cursor.close();
return contact;
}
The above does assumes that there will only be 1 row per email (which is most likely).
Explanations
A default value is set so that you can easily tell if an invalid/non-existent email is passed (you'd check the return value if need be (might be easier to simply have "" and check the length as a check)).
getReadableDatabase has been replaced with getWritableDatabase as unless there are issues with the database a writable database will be returned, as per :-
Create and/or open a database. This will be the same object returned
by getWritableDatabase() unless some problem, such as a full disk,
requires the database to be opened read-only. In that case, a
read-only database object will be returned. If the problem is fixed, a
future call to getWritableDatabase() may succeed, in which case the
read-only database object will be closed and the read/write object
will be returned in the future.
getReadableDatabase
Note no real problem either way;
The recommended query method has been used instead of the rawQuery method. This has distinct advantages, it builds the underlying SQL and also offers protection against SQL injection (just in case the email passed is input by a user).
this version of the method takes 7 parameters :-
The table name as a string
The columns to be extracted as an array of Strings (aka String array). null can be all columns.
The where clause less the WHERE keyword with ?'s to represent arguments (see next). null if no WHERE clause.
The arguments to be applied (replace ?'s 1 for 1) as a String array. null if none or no WHERE clause.
The GROUP BY clause, less the GROUP BY keywords. null if no GROUP BY clause.
The HAVING clause, less the HAVING keyword. null if no HAVING clause.
The ORDER BY clause, less the ORDER BY keywords. null if no ORDER BY clause.
SQLiteDatabase - query
- Note there are 4 query methods (see link for the subtle difference, I believe this is the most commonly used)
The data extraction is the new code. When a Cursor is returned it is at a position BEFORE THE FIRST ROW, so you need to move to a valid row. So the moveToFirst* method is suitable (note that if a move cannot be made by a move method that it will return false, hence how you can say if (cursor.moveToFirst())). The data is then extracted from the appropriate column use the **getString method, which takes an int as an argumnet for the column offset (0 in this case). However, using hard coded values can lead to issues so the getColumnIndex method is used to get the offset according to the column name (-1 is returned if the named column is not in the Cursor).
I tried to calculate a report and displays the result in the texview "edt1". But it's not displayed.
there is mydatabasehelper :
public void calculrapport(Argent a)
{
db = this.getWritableDatabase();
String query = "select sum(Entree) from Argent where date between \"datedebut\" and \"datefin\" ;";
Cursor cursor = db.rawQuery(query , null) ;
int count = cursor.getCount();
}
There is my class Rapport.java :
public void onOKClick ( View v ) {
if (v.getId() == R.id.okrapport) {
EditText datedebut = (EditText) findViewById(R.id.datedebut);
EditText datefin = (EditText) findViewById(R.id.datefin);
String strdatedebut = datedebut.getText().toString();
String strdatefin = datefin.getText().toString();
Argent a = new Argent();
helper.calculrapport(a);
edt1.setText( );
}
}
Thanks in advance.
Assuming that the query works as expected (especially considering that variables used have the appropriate scope, which would appear unlikely perhaps try using select sum(Entree) from Argent to test without the complications of wheteher or not the datedebut and datefin variables can resolve and if so resolve to usable values) then you need to :-
Extract the appropriate value and return the value from the method and then use the returned value to set the text in the TextView.
To return the value the method should not be void, but have an appropriate return type (String will be used for the example),
so instead of public void calculrapport(Argent a), use public String calculrapport(Argent a) (thus the method will be required to return a string)
To extract the value the cursor needs to be moved to the appropriate row (there should only be the one row as the sum function is an aggregate function and there is only the one group (aggregate functions work on gropus) i.e. all rows)
As such the method could be :-
public String calculrapport(Argent a)
{
String rv = "0"; //<<<< used to return 0 if no rows are selected by the query
db = this.getWritableDatabase();
String query = "select sum(Entree) from Argent where date between \"datedebut\" and \"datefin\" ;";
Cursor cursor = db.rawQuery(query , null) ;
if (cursor.moveToFirst()) {
rv = cursor.getString(0); //<<<< get the value from the 1st (only) column
}
cursor.close(); //<<<< Cursors should always be closed when done with
return rv;
}
To set the TextView with the returned value instead of using :-
helper.calculrapport(a);
edt1.setText( );
Use :-
edt1.setText(helper.calculrapport(a));
Or :-
String sum = helper.calculrapport(a);
edt1.setText(sum);
Additional re comment:-
The problem is located in the SQlite query (select sum(Entree) from
Argent where date between \"datedebut\" and \"datefin\" ;) exactly
when we call "datedebut" and "datefin" taht located in the class
rapport.java
Then String query = "select sum(Entree) from Argent where date between \"datedebut\" and \"datefin\" ;";
resolves to :-
select sum(Entree) from Argent where date between "datedebut" and "datefin" ;
I believe, assuming that datedebut and datefin are string variables, and that they are in a valid SQLite date format e.g. they could be 2018-01-01 and 2018-02-01 (and that values in the date column are formatted as a valid SQLite date format) that you should instead be using :-
String query = "select sum(Entree) from Argent where date between '" + datedebut + "' and '" + datefin +"' ;";
Which would then resolve to something like :-
SELECT sum(entree) FROM argent WHERE date BETWEEN '2018-01-01' AND '2018-02-01';
For valid SQLite date formats; refer to Date And Time Functions
Note the above is in-principle code and has not been tested so may contain some simple typing errors.
I am trying to create a fitness app where the database saves a username and password.
then enters their details that saves to a second table. This is my dbHelper.
The error im getting is that my "Username Column does not exist"
But when i go and look at my tables using db browser for sqlite
it shows my tables created and data in my tables
UPDATE : I created 1 table to store all my data and now its not picking up still im getting "not set" from my display method
updated table
// Register table
public static final String COL_1 = "ID";
public static final String COL_2 = "Username";
public static final String COL_3 = "Password";
public static final String COL_4 = "Weight";
public static final String COL_5 = "Height";
public static final String COL_6 = "TargetWeight";
public static final String COL_7 = "TargetSteps";
display method
public String DisplayData(String username,String column)
{
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_NAME +" WHERE Username =?",new String[]{username});
if(cursor.moveToFirst()){
return cursor.getString(cursor.getColumnIndexOrThrow(column));
}else{
return "Not set";
}
}
Usage
public void setData() {
db = new dbHelper(this);
try {
userWeight.setText(db.DisplayData(Username, dbHelper.COL_4));
userHeight.setText(db.DisplayData(Username, dbHelper.COL_5));
userTargetWeight.setText(db.DisplayData(Username, dbHelper.COL_6));
userTargetSteps.setText(db.DisplayData(Username, dbHelper.COL_7));
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
TABLE_NAME1 has no Username column. update your method as follow
public String DisplayData(String username, String column) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_NAME +" WHERE " + column + " = ? ", new String[]{username});
if (cursor != null && cursor.moveToFirst()){
return cursor.getString(cursor.getColumnIndexOrThrow(column));
} else {
return "Not set";
}
}
and use it like this
.DisplayData("admin", "Username");
Your issue, assuming that value of the 2nd argument of the Displaydata method is Username is that you are querying TABLE_NAME1 (profile_data) table, which doesn't have a column named Username.
Instead I believe you want to be querying the TABLE_NAME (register_table table) table so change :-
Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_NAME1 +" WHERE Username = 'admin' ",null);
to :-
Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_NAME +" WHERE Username = 'admin' ",null);
Additional re comment :-
Im not longer getting an error but its still not displaying the
correcting infomation . Im getting "Not set " from my displayData
method. from my if ELSE
Assuming that you have added data and getting the above then it is likely that Username does not equate to a row in the table. Try using the following version of DisplayData to debug :-
// Note changed to use recommended convenience query method
// Note closes cursor thus uses intermediate variable (rv) to allow close
public String DisplayData(String username,String column)
{
String rv = "Not set";
SQLiteDatabase db = this.getReadableDatabase();
//Cursor cursor = db.rawQuery("SELECT * FROM "+ TABLE_NAME +" WHERE Username =?",new String[]{username}); //<<<<< replaced
String whereclause = COL_2 + "=?";
String[] whereargs = new String[]{username};
Cursor cursor = db.query(TABLE_NAME,null,whereclause,whereargs,null,null,null);
//<<<<<<<<<< FOLLOWING CODE ADDED TO LOG DEBUG INFO >>>>>>>>>>
Log.d("DISPLAYDATAINFO","Display was called with Username as:- " +
username +
" for Column:- " +
column +
". The Cursor contains " +
String.valueOf(cursor.getCount()) +
" ."
);
//<<<<<<<<<< END OF ADDED DEBUG CODE >>>>>>>>>>
if(cursor.moveToFirst()){
rv = cursor.getString(cursor.getColumnIndexOrThrow(column));
}
cursor.close(); //<<<< SHOULD ALWAYS CLOSE CURSOR WHEN DONE WITH IT
return rv;
}
This should produce output in the log along the lines of :-
05-18 23:08:25.429 2926-2926/fitness.fitness D/DISPLAYDATAINFO: Display was called with Username as:- Fred for Column:- Weight. The Cursor contains 5 .
Display was called with Username as:- Fred for Column:- Height. The Cursor contains 5 .
Display was called with Username as:- Fred for Column:- TargetWeight. The Cursor contains 5 .
Display was called with Username as:- Fred for Column:- TargetSteps. The Cursor contains 5 .
Note 5 because when testing new data is inserted each run so the above indicates the 5th run.
Or in the case of nothing being found (your current issue) something like :-
05-18 23:11:40.342 2926-2926/fitness.fitness D/DISPLAYDATAINFO: Display was called with Username as:- Tom for Column:- Weight. The Cursor contains 0 .
Display was called with Username as:- Tom for Column:- Height. The Cursor contains 0 .
Display was called with Username as:- Tom for Column:- TargetWeight. The Cursor contains 0 .
Display was called with Username as:- Tom for Column:- TargetSteps. The Cursor contains 0 .
i.e. Cursor contains 0 = no rows exist for the given username (Tom in this case).
Check if the Username is as expected (note case of letters must match, in the above a row for tom exists but not for Tom hence 0 count for the cursor).
Column retrieval appears to be correct, However, still check that the columns in the output are as expected (can't see that they would not be).
I'm new to Android Studio and can't seem to find what I'm asking for.
I want to have a database that stores the data of a few people, e.g.
Steve Hardy, 16 Somewhere Land, Colorado, U.S.A.
I would like this to have headings (Name, Address, City, Country).
I'm just struggling with how to format a table like this and how I would link a database to this.
In android, mostly use sqlite databases. I can give you 3 simple functions I use to create database and table, insert data to table, & to read database values. If there is any unclear thing or you want any clarification, ask. I can help you.
public class MainActivity extends AppCompatActivity {
//Assign below 3 variables as global variables where class start.
SQLiteDatabase db; //Assign as a global variable
String DBName = "MyDB"; //Assign as a global variable
String TableName = "PeopleData"; //Assign as a global variable
//Call 3 function inside oncreate method.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createDB_Table(); //calling 3 functions.
InsertDataToDB();
ReadDBData();
}
public void createDB_Table(){ //This function use to create database, table & columns.
db = this.openOrCreateDatabase(DBName, MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS " + TableName + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT, Address TEXT, City TEXT, Country TEXT);");
db.close();
}
public void InsertDataToDB(){ //This function use to inset values to database.
db = this.openOrCreateDatabase(DBName, MODE_PRIVATE, null);
ContentValues cv = new ContentValues();
cv.put("Name","Steve Hardy");
cv.put("Address","16 Somewhere Land");
cv.put("City","Colorado");
cv.put("Country","USA");
db.insert(TableName, null, cv);
db.close();
}
public void ReadDBData() { //This function use to read data from database.
db = this.openOrCreateDatabase(DBName, MODE_PRIVATE, null);
Cursor cursor = db.rawQuery("SELECT * FROM " + TableName, null);
if (cursor.getCount() > 0) { //check cursor is not empty.
cursor.moveToFirst();
String DName = cursor.getString(cursor.getColumnIndex("Name"));
String DAddress = cursor.getString(cursor.getColumnIndex("Address"));
String DCity = cursor.getString(cursor.getColumnIndex("City"));
String DCountry = cursor.getString(cursor.getColumnIndex("Country"));
//Got the values from database. Then you can set those values to text view or something you use.
}
cursor.close();
db.close();
}
}
I have large number of strings, approximately 15,000 that I stored in a SQLite database using the following code:
void addKey(String key, String value, String table) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_KEY, key); // Contact Name
values.put(KEY_VALUE, value); // Contact Phone
// Inserting Row
db.insert(table, null, values);
db.close(); // Closing database connection
}
And then i search through that database using the following method in order to pick out any strings that match the key im looking for:
public String searchKeyString(String key, String table){
String rtn = "";
Log.d("searchKeyString",table);
// Select All Query
String selectQuery = "SELECT * FROM " + table;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Log.d("searchKeyString","searching");
if(cursor.getString(1).equals(key))
rtn = rtn + "," + cursor.getString(2);
} while (cursor.moveToNext());
}
cursor.close();
db.close();
Log.d("searchKeyString","finish search");
return rtn;
}
The goal is to do this in real time as the user is typing on the keep board so response time is key and the way it stands now it takes over a second to run through the search.
I considered reading all of the items into an array list initially and sorting through that which might be faster, but i thought an array list of that size might cause memory issues. What is the best way to search through these entries in my database?
A couple of things you can do...
Change the return to a StringBuilder until the end.
Only use a readable version of the database (that's probably not making much difference though)
Do not get a new instance of the database every time, keep it opened until you don't need it anymore
Query for only what you need with the "WHERE" argument in the SQL query.
See the code below with some changes:
// move this somewhere else in your Activity or such
SQLiteDatabase db = this.getReadableDatabase();
public String searchKeyString(String key, String table){
StringBuilder rtn = new StringBuilder();
Log.d("searchKeyString",table);
// Select All Query
String selectQuery = "SELECT * FROM " + table + " WHERE KEY_KEY=?";
Cursor cursor = db.rawQuery(selectQuery, new String[] {key});
// you can change it to
// db.rawQuery("SELECT * FROM "+table+" WHERE KEY_KEY LIKE ?", new String[] {key+"%"});
// if you want to get everything starting with that key value
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Log.d("searchKeyString","searching");
rtn.append(",").append(cursor.getString(2));
} while (cursor.moveToNext());
}
cursor.close();
Log.d("searchKeyString","finish search");
return rtn.toString();
}
Note even if you want this to happen in "real-time" for the user, you will still need to move this to a separate Thread or ASyncTask or you are going to run into problems....
You should consider using SELECT * FROM your-table LIMIT 50, for example. And you can put two buttons "Back", "Next" on your view. If every page has max 50 items, the user is at page 1, and he taps "Next", then you can use this query:
SELECT * FROM your-table LIMIT 50 OFFSET 50
If your table contains most of text-data, and you want to integrate search deeply into your app, consider using virtual table with FTS.
Let sqlite do the hard lifting.
First off, add an index to the field you're searching for, if you don't have one already. Secondly, don't do a SELECT all with manual table scan, but rather use a query in the form
SELECT column_value
FROM my_table
WHERE column_key LIKE "ABC%"
This returns the least amount of data, and the sql engine uses the index.
i dunno about better but maybe it'd be faster to make queries for the selected strings one by one.
public String searchKeyString(String key, String table){
String rtn = "";
Log.d("searchKeyString",table);
// Select All Query
String selectQuery = "SELECT * FROM " + table + "WHERE column_1 = " + key;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
rtn = rtn + "," + cursor.getString(2);
}
cursor.close();
db.close();
Log.d("searchKeyString","finish search");
return rtn;
}
EDIT:
Well i dunno how those custom keyboard apps do it, but those AutoCompleteTextViews are hooked up to adapters. you could just as easily make a cursorAdapter and hook your auto-complete view to it.
http://www.outofwhatbox.com/blog/2010/11/android-autocompletetextview-sqlite-and-dependent-fields/
http://www.opgenorth.net/blog/2011/09/06/using-autocompletetextview-and-simplecursoradapter-2/