I've been struggling a while with querying my SQLite database using one of my table field. I successfully query using the ForeignId field, but not with the Available field of my table QuizTable. I was hoping you could point out something I missed. Here is the call I make to the function queryQuiz. Please note the whereClause (kind of cut off) which is supposed to filter the available field for a value of 1. (side note: what if you want to query for different data types?)
QuizCursorWrapper cursor = db.queryQuiz(QuizTable.Cols.AVAILABLE + "=?", new String[]{"1"});
This is my queryQuiz function in a class that extends SQLiteOpenHelper.
Here's the error I am getting from calling queryQuiz:
Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
public QuizCursorWrapper queryQuiz(String whereClause, String[] whereArgs){
Cursor cursor = db.query(
QuizTable.NAME,
null,
whereClause,
whereArgs,
null,
null,
null
);
return new QuizCursorWrapper(cursor);
}
my QuizCursorWrapper class
public class QuizCursorWrapper extends CursorWrapper {
public QuizCursorWrapper(Cursor cursor){
super(cursor);
}
public String getQuiz(){
String paragraph = getString(getColumnIndex(QuizSchema.QuizTable.Cols.PARAGRAPH));
return paragraph;
}
public String getQuizUUID(){
String uuid = getString(getColumnIndex(QuizSchema.QuizTable.Cols.UUID));
return uuid;
}
}
and finally, my QuizSchema which defines the fields in my table.
public class QuizSchema {
public static final class QuizTable{
//nested class
public static final String NAME = "quizTable";
public static final class Cols{
public static final String SCORE = "score";
public static final String PARAGRAPH = "paragraph";
public static final String FOREIGNID = "foreignId";
public static final String UUID = "uuid";
public static final String AVAILABLE = "available";
}
}
}
I am very confused because I can clearly see rows with available fields equal to 1 in my quiz table . Sorry for the broad question, it's just that I can't put a finger on a problem and the debugger isn't too helpful. Please let me know if you need more info.
I believe that your issue is how column storage class/type affinity effects comparisons.
The solution is force the type affinity and thus how the comparisons are made. Forcing the type affinity can be achieved using CAST to set the type affinity.
As such a solution could be to CAST the values to type INTEGER for the comparison. You could do this by using :-
QuizCursorWrapper cursor = db.queryQuiz("CAST(" + QuizTable.Cols.AVAILABLE + " AS INTEGER) =CAST(? AS INTEGER)", new String[]{"1"});
You may wish to have a read of :-
Datatypes In SQLite Version 3
Related
Hi i'm still new in android and SQLite. I got activity which that can add query to my attached db file.
The problem is, i can't add data using my methods. Is there a simple methods to check if query is exists ?
Here is my DB Access
public class DBAccess {
private SQLiteOpenHelper openHelper;
private SQLiteDatabase db;
private static DBAccess instance;
Cursor c = null;
private DBAccess(Context context)
{
this.openHelper = new DatabaseOpenHelper(context);
}
public static DBAccess getInstance(Context context)
{
if(instance==null)
{
instance=new DBAccess(context);
}
return instance;
}
public void open()
{
this.db = openHelper.getWritableDatabase();
}
public void close()
{
if(db!=null)
{
this.db.close();
}
}
public void tambah(String a,String b)
{
String query= ("insert into TabelAbjad (kata,arti) values('"+a+"','"+b+"')");
db.execSQL(query);
}
public boolean checkdata(String c, String d)
{
String s;
String query= ("select kata from TabelAbjad where kata = '"+c+"' AND kata = '"+d+"'");
db.execSQL(query);
return true;
}
Here is when i try to call the methods
private void adddata()
{
DBAccess dbAccess = DBAccess.getInstance(getApplicationContext());
dbAccess.open();
String k = editkata.getText().toString().trim();
String a = editarti.getText().toString().trim();
if (dbAccess.checkdata(k,a))
{
Toast.makeText(this, "Data already exists",Toast.LENGTH_LONG).show();
dbAccess.close();
finish();
}
else
{
dbAccess.tambah(k,a);
dbAccess.close();
Toast.makeText(this, "Data Saved",Toast.LENGTH_LONG).show();
}
}
P.S : I'm call the method in button
You are missing a semicolon (;) in your query string.
Try this String query= ("select kata from TabelAbjad where kata = '"+c+"' AND kata = '"+d+"';"); for all your query strings
Your issue is that no row in the table will exist where the column kata has the value c as well as (AND) the value d it is impossible as a column can only have a single value, thus no rows would ever be extracted.
Perhaps you want to find rows that have either c OR d
in which case you could use :-
String query= ("select kata from TabelAbjad where kata = '"+c+"' OR kata = '"+d+"'");
i.e. AND has been changed to OR
Furthermore, execSQL cannot return a result, as per :-
Execute a single SQL statement that is NOT a SELECT or any other SQL
statement that returns data. execSQL
You thus need to either use the rawQuery method or the convenience query method, the latter recommended unless it's limitations mean that it cannot be used. As such you should try using something along the lines of (OR instead of AND assumed) :-
public boolean checkdata(String c, String d)
boolean rv = false;
String whereargs = "kata=? OR kata=?"; // the WHERE clause less the WHERE keyword ? for the arguments (used on a 1 for 1 basis)
String[] whereargs = new String[]{c,d}; // The arguments that will be substituted into the SQL
String[] columns = new String[]{"kata"};
Cursor csr = db.query("TabelAbjad",columns,whereclause,whereargs,null,null,null);
if (csr.getCount() > 0) {
rv = true;
}
csr.close();
return rv;
}
Although this may appear to be more complex to code it has advantages as it build the underlying SQL, it protects against SQL injection and it correctly encloses/escapes (wraps the values in single quotes etc) the values)arguments
You retrieve data (rows) into a Cursor (in this case you simply want to know if any rows matched the given criteria so getCount() is used (it returns the number of rows extracted which could be 0 if none)).
Is there a simple methods to check if query is exists ?
I believe that what you really mean is there anyway to check if the query returned any results.
As said above a query returns data via a Cursor (like a table but according to the query e.g. the Cursor above will consist of a number of rows (0 or more) with a single column named kata (i.e. the query is SELECT **kata** FROM .....) ) and thus you need to use a suitable method.
You can check/access numerous aspects/properties. Typically you'd move around the Cursor (e.g. while (your_cursor.moveToNext) {.... do things ....} can be used traverse all rows in the cursor). Cursor.
Once positioned appropriately at a row then you can use the get????(column_offset) to retrieve the data that came from the database (where column_offset is an integer with 0 representing the first column, however it is generally much wiser to retrieve the actual offset using the getColumnIndex(column_name_as_a_string method.))
So assuming that you wanted the data (String) in the first row that was extracted above into the Cursor csr then you could use :-
if (csr.moveToFirst()) {
String mykata = csr.getString(csr.getColumnIndex("kata"));
}
csr.close(); // You should always close a cursor when done with it.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to create a SQLite database for the game Tic Tac Toe on Android Studio that has the names and score of the players. Every time a user win, a point is added on the scoreboard.
How would I do this?
Stage 1 - Database Design
First design the database, you have identified Data as User name, and score, assuming you don't want historical data then a single table would suffice.
So design would be a table, perhaps called scoreboard, with columns :-
username
score and
To perhaps aid future changes a column name id that uniquely identifies a user (e.g. say you had two Toms or even two Tom smiths), this identifier (which is generally available) will be an alias of rowid. As Cursor Adapters require the id to be named _id then that will be used.
As such you could have a table that is created using the following SQL :-
CREATE TABLE IF NOT EXISTS scoreboard
(
_id INTEGER PRIMARY KEY,
username TEXT,
score INTEGER
);
Stage 2 - Creating the Database
When getting started with SQLite for Android it is probably best to utilise a subclass of SQLiteOpenHelper as what many refer to as the DBHelper.
So create a class say DBHelper.java which extends the SQLiteOpenHelper class.
Note you must include overrides for the onCreate method and the onUpgrade method.
If using Android Studio when adding a new class;
input, DBHelper in the **Name* field,
type SQLiteOpenHelper in the Superclass field (by the time you've typed SQL you will see SQLiteOpenHelper double click is) and
then tick/check the Show Select Overrides Dialog.
Click OK
You will presented with the Overrides Dialog select (Ctrl + CLick) the following 3 (SQLiteOpenHelper(context"Context,name:String,factory:CursorFactory,version:int) will be selected) :-
SQLiteOpenHelper(context"Context,name:String,factory:CursorFactory,version:int)
onCreate(.....
onUpgrade(.....
Then click OK.
You will then have :-
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
Define some constants
Between the class and the constructor add some constants so you have a single source for names of tables/columns etc e.g. :-
public static final String DBNAME = "tictactoe.db"; // Database name
public static final int DBVERSION = 1; // Database version #
public static final String TB_SCOREBOARD = "scoreboard"; // table name
public static final String COL_SCOREBOARD_ID = BaseColumns._ID; // use default id column name
public static final String COL_SCOREBOARD_USERNAME = "username";
public static final String COL_SCOREBOARD_SCORE = "score";
Ready to create the Table
The onCreate method will be called when you try to open the database (and the database is actually created). Generally it is here that you create the tables.
Note one of the more common issues newcomers have is that they think that onCreate runs every time a database is opened. It is not it only runs once when the database is first created.
as such any changes (say you add a new column) WILL NOT BE MADE if the databade still exists (easiest solution when developing an App is to delete the App's Data or uninstall the App and rerun the App).
So in the onCreate method :-
create a String of the SQL to create the table (i.e. the CREATE IF NOT EXISTS.... previously shown). However, do so utilising the CONSTANTS (see below).
call the SQLiteDatabase execSQL method to run the SQL.
Alter the constructor's signature (make it easier to call).
As the database name and version are known (they are constant) and that a cursor factory needn't be used (null will signify this) the super call in the constructor can be replaced with :-
super(context, DBNAME, null, DBVERSION);
Therefore the signature for the DBHelper class can be changed to :-
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
}
So the DBHelper class in full (at present) can be :-
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "tictactoe.db"; // Database name
public static final int DBVERSION = 1; // Database version #
public static final String TB_SCOREBOARD = "scoreboard"; // table name
public static final String COL_SCOREBOARD_ID = BaseColumns._ID; // use default id column name
public static final String COL_SCOREBOARD_USERNAME = "username";
public static final String COL_SCOREBOARD_SCORE = "score";
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String crtsql = "CREATE TABLE IF NOT EXISTS " +
TB_SCOREBOARD + // The table name
"(" +
COL_SCOREBOARD_ID + " INTEGER PRIMARY KEY," + //The _id column
COL_SCOREBOARD_USERNAME + " TEXT, " + // username column
COL_SCOREBOARD_SCORE + " INTEGER" + // score column (no trailing comma as last)
")" ;
sqLiteDatabase.execSQL(crtsql);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
Stage 3 - TEST what has been so far
Believe it or not the above is sufficient to create the database and the table and hence the columns within the table (not to actually add any data or anything useful but at least).
Typically you would use the database in an activity. For the purposes of this testing a basic MainActivity will be used.
It's actually very simple we just create a DBHelper instance (passing the Context).
BUT doing so won't create a database it's only when either the getWritableDatabase or getReadableDatabase methods are called that an attempt is made to open or create the database. So a second line will do this (could be done in one line) :-
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DBHelper mDBHlpr = new DBHelper(this); // get DBHelper instance
mDBHlpr.getWritableDatabase(); // force an open (wouldn't normally do this)
}
}
Note you wouldn't normally have a call to getWritableDatabase as will be seen each method to access the table(s) will do this, so the very first time one of these would result in the onCreate method being called.
Note there is much confusion with getReadableDatabase, in short it doesn't make it so you can't update/change data unless the database can only be read.
i.e. getReadabledatabase will get a writable database unless in the very rare scenario the database can only be read (when getWritableDatabase would fail with an unable to open database error).
VERY RARELY is there any use coding getReadableDatabase.
Do the above and Run the App - nothing much will happen, but hopefully it shouldn't crash.
Now if you can (depends on emulator (I use genymotion which gives you root access)) use Android Studion's Device Explorer* to look at **/data/data/<your_package_name>/databases/ and hopefully you will see :-
package and actual database are highlighted.
database is just a file (can be copied and opened in other SQLite tools (can even be copied to android (emulator/device permitting))).
journal is SQLite's file that records what's being done and in cases of errors allows data to be rolled back (i.e. just accept it exists).
A believe that size should be 16K (depends upon data and structure of the database). It shouldn't be 0 though.
If you can't use Device Explorer then you can go into settings and check the App's data (if you have other uses of App data then check subtract this (check before running)), it should be 0 (after subtracting other data). in which case that's an indication that the database exists.
Stage 4 - Adding and Manipulating Data
At this stage a database exists with a table but no data itself exists. So a means of adding data (inserting rows) (a table has rows a row consisting of the columns as per the definition of the table).
It's no use adding data unless that data can be accessed so a means of extracting the data (querying) is required.
As a method of changing (updating) the score is required a means of doing this is required.
So what is needed now are 3 things :-
an insertRow method
a getAllData method (say to list scoreboard)
a updateScore method (which will adjust the score according to a number)
Typically such methods are added to the Database Helper (so they will be here)
The insertRow method
When inserting a row we need to add the name and the score (we could have defined the score column as score INTEGER DEFAULT 0 and then just the name would be required).
Although you don't know it yet id's can be very useful so the method will return the id of the newly inserted row, which due to using _id INTEGER PRIMARY KEY (and specifically this (or INTEGER PRIMARY KEY AUTOINCREMENT). will be generated automatically (i.e. the _id column is an alias of the very special but normally hidden rowid column (see link below for more info on rowid)).
the latter, AUTOINCREMENT, is very rarely needed but is seen very often more here SQLite Autoincrement, this also explains rowid)
So a method such as the following could be added :-
public long insertRow(String username, int initial_score) {
// SQL equivalent of :-
// INSERT INTO scoreboard (username,score) VALUES('the user name',0)
ContentValues cv = new ContentValues(); // Used by convenience method for column/value pairs
cv.put(COL_SCOREBOARD_SCORE,username); // The username to be added
cv.put(COL_SCOREBOARD_SCORE,initial_score); // The score to be added
SQLiteDatabase db = this.getWritableDatabase(); // Get a SQLiteDatabase instance
return db.insert(TB_SCOREBOARD,null,cv); // Insert it using conveniece method
/*
Note if row cannot be inserted then return will be -1
If inserted the id will be returned,
first ever insert will be 1,
then likely 2
then likely 3
NEVER ASSUME 1,2,3.......... though
ALWAYS ASSUME IT WILL BE A UNIQUE VALUE
i.e. NEVER CODE SPECIFIC ID's
*/
}
You may wish to read insert
The Activity could use this using for example :-
mDBHlpr.insertRow("Rumplestiltskin the 3rd",10000000); // The winner :)
mDBHlpr.insertRow("Fred Blogs",0); // New user would normally start with score 0
Adds 2 rows first with high score, 2nd as you would probably add a new user
The getAllData method
With Android you extract data into what's called a Cursor, which is like a spreadsheet it has rows and columns (columns as you specify so they needn't be all the columns, can also be other columns (e.g. derived/calculated or from other tables).
You create a Cursor (at least a normal one) by querying the table or tables in the database (note this doesn't cover all aspects). So use will be made of the convenience query method (well 1 of the 4) using :-
public Cursor getAlldata() {
// The columns to retrieve
String[] columns = new String[]{
COL_SCOREBOARD_ID,
COL_SCOREBOARD_USERNAME,
COL_SCOREBOARD_SCORE
};
// NOTE normally for all columns you would use the above but
// instead pass null as the 2nd parameter to the query method
return this.getWritableDatabase().query(
TB_SCOREBOARD,
columns,
null,
null,
null,
null,
null
);
}
You may wish to read query
This could be used in the Activity along the lines of :-
Cursor csr = mDBHlpr.getAlldata();
csr.close(); //YOU SHOULD ALWAYS CLOSE A CURSOR WHEN DONE WITH IT
The updateScore method
Without getting too complex and sticking to convenience methods the process of updating a score will :-
get the old score (according to id)
update the new score by adding the new score (if it's minus then reducing the score)
As such 2 parameters are required the id and the amount to adjust the score by.
-Id's should be long (you will see many uses of int but long copes with all possible id's).
-adjustment will be integer (long if very high scores are expected)
A diversion for getScoreById method
As getting a user's score may be useful another method will be created to do this. This also makes use of a Cursor that selects specific data rather than all via an SQL WHERE clause. So a method getScoreById will also be created. This will return the current score as an int and is passed a long as the id.
This could be :-
public int getScoreById(long id) {
int rv = -1; // just in case the id doesn't exist return -1 so invalid adjustment can be detected
String[] columns = new String[]{COL_SCOREBOARD_SCORE}; // only want the score
String whereclause = COL_SCOREBOARD_ID + "=?"; // will be WHERE _id=? (? replaced by respective whereargs element)
String[] whereargs = new String[]{String.valueOf(id)}; // ? will be replaced with id
Cursor csr = this.getWritableDatabase().query(
TB_SCOREBOARD,
columns,
whereclause,
whereargs,
null,
null,
null
);
if (csr.moveToFirst()) {
//rv = csr.getInt(0); // Hard coded column offsets bad so :-
rv = csr.getInt(csr.getColumnIndex(COL_SCOREBOARD_SCORE));
}
csr.close(); // Done with the cursor so close it
return rv; // return the current score
}
Back to the upDateScore method
Now that the score can be retrieved by the id via the getScoreById method then the the updateScore method could be :-
public boolean updateScore(long id, int adjustment) {
int newscore = getScoreById(id) + adjustment; // get the new score
// Check that the new score is valid (i.e. greater than 0)
// If it's invalid then don't do update by returning false but after
// issuing a message to the log (for development should be removed for production)
if (newscore < 0) {
Log.d("INVALIDSCORE",
"An invalid new score (less than 0) was returned. Update cancelled.");
return false;
}
// Prepare to use the update convenience method
String whereclause = COL_SCOREBOARD_ID + "=?";
String[] whereargs = new String[]{String.valueOf(id)};
ContentValues cv = new ContentValues();
cv.put(COL_SCOREBOARD_SCORE,newscore);
SQLiteDatabase db = this.getWritableDatabase();
// WARNING without a WHERE clause update would update ALL ROWS
// update returns number of rows updated as an int, so if this is
// greater than 0 true is returned else false.
return db.update(TB_SCOREBOARD,cv,whereclause,whereargs) > 0;
}
So the whole DBHelper class could be :-
public class DBHelper extends SQLiteOpenHelper {
public static final String DBNAME = "tictactoe.db"; // Database name
public static final int DBVERSION = 1; // Database version #
public static final String TB_SCOREBOARD = "scoreboard"; // table name
public static final String COL_SCOREBOARD_ID = BaseColumns._ID; // use default id column name
public static final String COL_SCOREBOARD_USERNAME = "username";
public static final String COL_SCOREBOARD_SCORE = "score";
public DBHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String crtsql = "CREATE TABLE IF NOT EXISTS " +
TB_SCOREBOARD + // The table name
"(" +
COL_SCOREBOARD_ID + " INTEGER PRIMARY KEY," + //The _id column
COL_SCOREBOARD_USERNAME + " TEXT, " + // username column
COL_SCOREBOARD_SCORE + " INTEGER" + // score column (no trailing comma as last)
")" ;
sqLiteDatabase.execSQL(crtsql);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public long insertRow(String username, int initial_score) {
// SQL equivalent of :-
// INSERT INTO scoreboard (username,score) VALUES('the user name',0)
ContentValues cv = new ContentValues(); // Used by convenience method for column/value pairs
cv.put(COL_SCOREBOARD_SCORE,username); // The username to be added
cv.put(COL_SCOREBOARD_SCORE,initial_score); // The score to be added
SQLiteDatabase db = this.getWritableDatabase(); // Get a SQLiteDatabase instance
return db.insert(TB_SCOREBOARD,null,cv); // Insert it
/*
Note if row cannot be inserted then return will be -1
If insert the id will be returned,
first ever insert will be 1,
then likely 2
then likely 3
NEVER ASSUME 1,2,3.......... though
ALWAYS ASSUME IT WILL BE A UNIQUE VALUE
i.e. NEVER CODE SPECIFIC ID's
*/
}
public Cursor getAlldata() {
// The columns to retrieve
String[] columns = new String[]{
COL_SCOREBOARD_ID,
COL_SCOREBOARD_USERNAME,
COL_SCOREBOARD_SCORE
};
// NOTE normally for all columns you would use the above but
// instead pass null as the 2nd parameter to the query method
return this.getWritableDatabase().query(
TB_SCOREBOARD,
columns,
null,
null,
null,
null,
null
);
}
public boolean updateScore(long id, int adjustment) {
int newscore = getScoreById(id) + adjustment; // get the new score
// Check that the new score is valid (i.e. greater than 0)
// If it's invalid then don't do update by returning false but after
// issuing a message to the log (for development should be removed for production)
if (newscore < 0) {
Log.d("INVALIDSCORE",
"An invalid new score (less than 0) was returned. Update cancelled.");
return false;
}
// Prepare to use the update convenience method
String whereclause = COL_SCOREBOARD_ID + "=?";
String[] whereargs = new String[]{String.valueOf(id)};
ContentValues cv = new ContentValues();
cv.put(COL_SCOREBOARD_SCORE,newscore);
SQLiteDatabase db = this.getWritableDatabase();
// WARNING without a WHERE clause update would update ALL ROWS
// update returns number of rows updated as an int, so if this is
// greater than 0 true is returned else false.
return db.update(TB_SCOREBOARD,cv,whereclause,whereargs) > 0;
}
public int getScoreById(long id) {
int rv = -1; // just in case the id doesn't exist return -1 so invalid adjustment can be detected
String[] columns = new String[]{COL_SCOREBOARD_SCORE}; // only want the score
String whereclause = COL_SCOREBOARD_ID + "=?"; // will be WHERE _id=? (? replaced by respective whereargs element)
String[] whereargs = new String[]{String.valueOf(id)}; // ? will be replaced with id
Cursor csr = this.getWritableDatabase().query(
TB_SCOREBOARD,
columns,
whereclause,
whereargs,
null,
null,
null
);
if (csr.moveToFirst()) {
//rv = csr.getInt(0); // Hard coded column offsets bad so :-
rv = csr.getInt(csr.getColumnIndex(COL_SCOREBOARD_SCORE));
}
csr.close(); // Done with the cursor so close it
return rv; // return the current score
}
}
Stage 5 - Testing
The activity (based upon a new empty project) could now be :-
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DBHelper mDBHlpr = new DBHelper(this); // get DBHelper instance
//mDBHlpr.getWritableDatabase(); // force an open (wouldn't normally do this) Not needed now
mDBHlpr.insertRow("Rumplestiltskin the 3rd",10000000); // The winner :)
mDBHlpr.insertRow("Fred Blogs",0); // New user would normally start with score 0
mDBHlpr.updateScore(1,-9999999); //Set Rumplestiltskins's score to 0
// NOTE id should be 1 BUT hard coding id's is
// should be avoided (just used for demo purposes)
mDBHlpr.updateScore(2,1); // Increment Fred's score (see above re hard coded id's)
Cursor csr = mDBHlpr.getAlldata();
StringBuilder sb = new StringBuilder();
// Do something with the Extracted Data
while (csr.moveToNext()) { // Loop through all rows
long userid = csr.getLong(csr.getColumnIndex(DBHelper.COL_SCOREBOARD_ID));
String username = csr.getString(csr.getColumnIndex(DBHelper.COL_SCOREBOARD_USERNAME));
int userscore = csr.getInt(csr.getColumnIndex(DBHelper.COL_SCOREBOARD_SCORE));
sb.append("\n\tUsername=");
sb.append(username);
sb.append((" (ID="));
sb.append(userid);
sb.append(") Score=");
sb.append(userscore);
sb.append(".");
}
csr.close();
Log.d("SCOREBOARD",sb.toString());
}
}
Note cursor handling added
Result
note after numerous runs which will add duplicate usernames but with different id's)
:-
05-18 12:09:46.750 3018-3018/? D/INVALIDSCORE: An invalid new score (less than 0) was returned. Update cancelled.
05-18 12:09:46.754 3018-3018/? D/SCOREBOARD: Username=null (ID=1) Score=1.
Username=null (ID=2) Score=5.
Username=null (ID=3) Score=10000000.
Username=null (ID=4) Score=0.
Username=null (ID=5) Score=10000000.
Username=null (ID=6) Score=0.
Username=null (ID=7) Score=10000000.
Username=null (ID=8) Score=0.
Username=null (ID=9) Score=10000000.
Username=null (ID=10) Score=0.
Invalid Score is because once ID 1 is down to 1 the adjustment of -99999999 will be less than 0.
ID 2's score is 5 due to 5 runs (i.e. 10 rows/users).
Note
The above is a fully working albeit it not that useful, introduction/answer. As such any subsequent questions should really be other questions on Stack Overflow.*
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm a windows phone developer and newly I started developing android apps using android studio.
I need to create a database and store in it values and retrieve the updated values on screen, so I need help in:
Creating the database.
How to show values from the database on screen?
to create database , you need to extend SQLiteOpenHelper and need a constructor that takes Context.
lets say you name this class DBOperator. The table creation process will look something like this ,
public class DbOperator extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "DB_NAME";
protected static final String FIRST_TABLE_NAME = "FIRST_TABLE";
protected static final String SECOND_TABLE_NAME = "SECOND_TABLE";
public static final String CREATE_FIRST_TABLE = "create table if not exists "
+ FIRST_TABLE_NAME
+ " ( _id integer primary key autoincrement, COL1 TEXT NOT NULL, COL2 TEXT NOT NULL,COL3 TEXT, COL4 int, COL5 TEXT,"
+ "COL6 TEXT,COL7 REAL, COL8 INTEGER,COL9 TEXT not null);";
public static final String CREATE_SECOND_TABLE = "create table if not exists "
+ SECOND_TABLE_NAME+.........
public DbOperator(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_SFIRST_TABLE);
db.execSQL(CREATE_SECOND_TABLE);
//db.close();
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//THIS WILL BE EXECUTED WHEN YOU UPDATED VERSION OF DATABASE_VERSION
//YOUR DROP AND CREATE QUERIES
}
}
Now your data manipulation class ( add, delete , update ) will look something like this ,
public class FirstTableDML extends DbOperator {
public FirstTableDML(Context context) {
super(context);
}
private static final String COL_ID = "_id";
private static final String COL1 = "COL1";
private static final String COL2 = "COL2";
........
.......
public void deleteFirstTableDataList(List<FirstTableData> firstTableDataList) {
for (FirstTableData data : firstTableDataList)
deleteFirstTableDetailData(data);
}
public void deleteFirstTableDetailData(FirstTableData item) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(FIRST_TABLE_NAME, item.getId() + "=" + COL_ID, null);
db.close();
}
/**this method retrieves all the records from table and returns them as list of
FirstTableData types. Now you use this list to display detail on your screen as per your
requirements.
*/
public List< FirstTableData > getFirstTableDataList() {
List< FirstTableData > firstTableDataList = new ArrayList< FirstTableData >();
String refQuery = "Select * From " + FIRST_TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(refQuery, null);
try {
if (cursor.moveToFirst()) {
do {
FirstTableData itemData = new FirstTableData();
itemData.setId(cursor.getInt(0));
itemData.setCol1(cursor.getString(1));
itemData.setCol2(cursor.getInt(2));
.....
.....
firstTableDataList.add(itemData);
} while (cursor.moveToNext());
}
} finally {
db.close();
}
Collections.sort(itemDataList);
return itemDataList;
}
public int addFirstTableData(FirstTableData data) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COL1, data.getCol1());
values.put(COL2, data.getCol2());
.....
.....
long x=db.insert(FIRST_TABLE_NAME, null, values);
db.close();
return (int)x;
}
public void updateItemDetailData(FirstTableData data) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COL1, data.getCol1());
values.put(COL2, data.getCol2());
values.put(COL3, data.getCol3());
.....
.....
db.update(FIRST_TABLE_NAME, values, COL_ID + "=" + data.getId(), null);
db.close();
}
}
P.S : *Data class are POJO data class representing the corresponding table.
Since you said you are not totally new to these, I have not provided any helper comments as most of the method names are self explanatory.
Hope it helps you to get started.
To creating a database for Android application, there are 2 ways:
Create database and tables using Code
Use existing database
1) Create database and tables using Code
In this scenario, you have to write a class and code to create database and tables for it. You have to use different classes and interfaces like SQLiteOpenHelper, SQLiteDatabase, etc. Check answer posted by Jimmy above.
2) Use existing database
In this scenario, you can use your existing sqlite database inside your android application. You have to place database file inside assets folder and write a code to copy that existing database on to either internal or external storage.
Regarding best scenario, I would say it's depend on the application functionality and nature, if your database is small then you should go with 1st scenario and if your database is large with many tables then you should go with 2nd scenario because you would be creating database using any GUI based SQLite browser and which would help you to make less mistakes. (When I say less mistakes using GUI, believe me there are chances of creating tables by code).
How to show values from the database on screen?
For that you have to write a SQL query which gives you Cursor in return which is a set of resultant data, so you have to iterate through the cursor data and prepare a set of data in terms of ArrayList or Array or HashMap.
You can display this set of data in ListView or GridView.
P.S. I am not posting links to any tutorials or examples as there are plenty of information/examples available on web, so suggesting you to search around the given points.
A good way to start is to read about Storage Options on the official Android documentation website: http://developer.android.com/guide/topics/data/data-storage.html
I have one strange issue. I am fetching data from server and inserting it into tables. After insertion I query that data using inner join between two tables.
here is my query :
Select
F._id, F.id, F.logo, F.total_like, F.distance, F.store_name, F.mob_no_1,
F.mob_no_2, F.mob_no_3, F.tel_no_1, F.tel_no_2, F.tel_no_3, F.description,
R.total_record, R.total_page, R.current_page
from
FAVOURITE_STORES as F
INNER JOIN FAVOURITE_RECORDS as R on F.area_id = R.area_id
where
F.area_id = 2 and
R.area_id = 2
I get the cursor count as 1 on some devices and on some devices I get cursor count as zero. Even if the data is there in table.
here is my select query function
public Cursor rawQuery(String sQuery,String[] selectionArgs) {
if(mDatabase == null) {
mDatabase = getWritableDatabase();
}
debug("Query "+sQuery);
return mDatabase.rawQuery(sQuery,selectionArgs);
}
Cursor class
public class ExampleCursorLoader extends CursorLoader {
private Activity mActivity;
private String msQuery;
private DBUtil mDbUtil;
private String[] mSelectionArgs;
public ExampleCursorLoader(Activity context, String query,String[] selectionArgs) {
super(context);
this.mActivity = context;
this.msQuery = query;
this.mSelectionArgs = selectionArgs;
this.mDbUtil = DBUtil.getInstance(mActivity.getApplicationContext());
}
public ExampleCursorLoader(Activity context, String query) {
this(context,query,null);
debug(query);
}
public Cursor loadInBackground() {
debug("Loading in Background");
Cursor cursor=null;
cursor = mDbUtil.rawQuery(msQuery,mSelectionArgs);
return cursor;
}
private void debug(String s) {
Log.v("Adapter " , "Adapter " + s);
}
protected void onStartLoading() {
forceLoad();
debug("Started Loading");
}
protected void onStopLoading() {
super.onStopLoading();
}
}
and this is how I am calling it.
return new ExampleCursorLoader(mActivity,sQuery);
Device that gives count as 1 is Samsung s3. And zero is Samsung Grand.
Have any thought or suggestion on this?
Device that gives count as 1 is Samsung s3. And zero is Samsung Grand.
Have any thought or suggestion on this?
This kind of problem is hard to explain because most likely it doesn't throw any error but only shows different and unwanted result.
All what you are able to do is to "improve query":
At first use placeholders and not raw statements:
String query = "... where F.area_id = ? and R.area_id = ?";
String[] whereArgs = {"2", "2"};
Also you don't need to use AS clause, it's enough to say:
... from FAVOURITE_STORES F INNER JOIN FAVOURITE_RECORDS R on ...
From code that you provided everythings seems correct (query and an usage of rawQuery()).
It seems to me that the last section of your WHERE-clause is unnecessary:
and R.area_id=2
You've already specified the rows for the FAVOURITE_STORES table to match area_id=2. As the INNER JOIN is performed on that column, it will only return the rows from FAVOURITE_RECORDS where the area_id column matches FAVOURITE_STORES' area_id column.
I'm not sure how the SQLite engine handles this, but it's worth a try.
HELP! Okay so I have been designing an android app for quite some time now and I have been manually putting all this data into strings and then just pulling them up in my layouts, but then a friend of mine suggested I put all the necessary data into a database and then just pull it out of there on each activity....sounds good....Accept I have been reading tutorial after tutorial on how this works and it seems much harder than just making lots and lots of strings and the examples in the tutorials each serve their own purpose which is not mine and dose not make understanding any easier for me. All I will be needing this database to do is read and display the info where I want it on the layouts. I created this database with SQLite Database Browser.
Database structure:
Name - fishindex_db
Tables - fish, states, reg
Rows:
fish - _id, name, desc, loc
states - _id, name, abbr, updated
reg - _id, name, size, season, quantity, notes
so now say I want to display all the content from primary key (_id) 12 from the reg table in a layout list view how is this done? need .java and .xml code example please.
These are two tutorials you can use to get you up and running in terms of what you want to achieve:
Android SQLite Database Tutorial
How to connect Android with PHP, MySQL - this one takes it a bit further in showing you how to connect to production databases and consume web services.
Hope this helps.
Take a look at the code to connect to fishindex_db
public class SQLiteHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "fishindex_db.db";
public static final String TABLE_NAME = "fish";
public static final String _id = "id";
public static final String name = "name";
public static final String desc = "desc";
private SQLiteDatabase database;
SQLiteHelper sQLiteHelper = new SQLiteHelper(MainActivity.this);
public SQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//this is to get all records in fish table
public ArrayList<FishModel> getAllRecords() {
database = this.getReadableDatabase();
Cursor cursor = database.query(TABLE_NAME, null, null, null, null, null, null);
ArrayList<FishModel> fishes= new ArrayList<FishModel>();
FishModel fishModel;
if (cursor.getCount() > 0) {
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToNext();
fishModel= new FishModel();
fishModel.setID(cursor.getString(0));
fishModel.setName(cursor.getString(1));
fishModel.setLastName(cursor.getString(2));
fishes.add(fishModel);
}
}
cursor.close();
database.close();
return contacts;
}