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.
Related
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.*
I am trying to display value of a particular row in android to check if a particular updation. Can I made it successful or not? But as the return type is cursor I don't know how to fetch it. So pls help me.
public Cursor getData(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from calls where id=" + id + "", null);
return res;
}
Try this...
ArrayList<HashMap<String, String>> dataList = new ArrayList<>();
call your method to get data as arraylist of hashmap
dataList.addAll(loginDataBaseAdapter.getData(id));
or
dataList = loginDataBaseAdapter.getData(id);
in db_class
public ArrayList<HashMap<String, String>> getData(String id) {
ArrayList<HashMap<String, String>> returnArray = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from calls where id=" + id + "", null);
if (res != null && res.getCount() > 0) {
if (res.moveToLast()) {
do {
HashMap<String, String> getdatamap = new HashMap<String, String>();
getdatamap.put("KEY_ONE", res.getString(1));
getdatamap.put("KEY_TWO, res.getString(2));
returnArray.add(getdatamap);
}while (res.moveToPrevious());
}
}
res.close();
return returnArray;
}
Now you can use the values in arraylist to make your view
You can follow the below code:
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from calls where id=" + id + "", null);
if (res != null) {
res.moveToFirst();
}
String firstColumnValue = res.getString(0);
String secondColumnValue = res.getString(1);
And close the database after retrieving values:
db.close();
If you want to get column value by its name, then use the following code:
String value = res.getColumnIndex("column_name");
Get row value as a String. Then return string value.
public String getData(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("select * from calls where id=" + id + "", null);
if (res.getCount() > 0) {
res.moveToFirst();
String s = res.getString(res.getColumnIndex("id"));
return s;
}
There are two factors that need to be considered when retrieving data from a cursor; which row (position within the cursor) and then column and it's type.
To position the Cursor you use one of the Cursor's move methods. These are :-
move, which moves the cursor relevant to it's current position.
moveToFirst
moveToLast
moveToNext
moveToPosition and
moveToPrevious
All return true if the move could be performed otherwise false.
A cursor can be empty and have no rows, so movetoFirst would return false.
One of the more common usages is :-
while (cursor.moveToNext) {
.... cursor action(s) here.
}
A Cursor will initially be positioned to before the first row i.e. it's position is -1 and can be set using moveToPosition(-1).
The Cursor's getPosition method will retrieve the current position, noting that the first row is position 0.
Column's in rows are accessed according to the offset (which column) and the Cursor's get???? (where ???? represents type) methods are used to retrieve the data from the row/column (there are other get.... methods e.g. getPosition as above). The methods for retrieving the data are:-
getBlob (retrieves a byte array).
getDouble
getFloat
getInt
getLong
getShort
getString
All take a single parameter, an integer that is the column's offset within the cursor (which is not necessarily the offset in the table).
You can use any on any type of data, with the exception of blobs. An attempt to use any, except getBlob, on a BLOB will result in an exception.
However, the results, can vary e.g. if you use get, for example assuming column with offset 0 contains *rumplestilskin then :-
cursor.getString(0) will return rumplestiltskin
cursor.getDouble(0) will return 0 as a double.
cursor.getInt(0) will return 0 as a float.
.....
In short, you should use the appropriate get method, otherwise the results could be confusing.
Hard coding column column offsets, often results in issues therefore it is generally better to use column names in conjunction with the Cursor's getColumnIndex method. This takes a String, the column name, as a parameter and returns the offset of the column.
Applying the above to the question:-
Code that could be useful (i.e. it retrieves data) could be :-
Cursor csr = db.getData(myid);
while (csr.moveToNext) {
long id_of_the_row = csr.getLong(csr.getColumnIndex(yourDatabaseHelperClass.id));
}
Noting:-
if (moveToFirst(myid)) { .... } could be considered more correct but assuming that just a single row exists bot moveToFirst and moveToNext, as coded, produce the same result.
Assuming that the id column is an alias of the rowid, then rowid is stored as a long and should properly be extracted as a long.
yourDatabaseHelperClass.id will not be correct, rather you would replace it with the class that extends SQLiteOpenHelper (the class that contains your getData method), it also assumes that variable id has public access.
Links that may be useful or of interest:-
Cursor
How flexible/restricive are SQLite column types?
(includes examples of how some of the Cursor get???? methods retrieve data)
Are there any methods that assist with resolving common SQLite issues?
ok I just followed an instruction that I should do this to retrieve sql data from database but it just cuts to there so far I have this inside my databasehelper class.
public void getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
}
while (cursor.moveToNext());
}
db.close();
}
So somehow this does is it get all the values of my tables 4th column which contains an int... how do I retrieve the value in my MainActivity and save it in an array of integers?
just add everything in a ArrayList and return the arraylist
simply call the method in your main activty
public ArrayList<Integer> getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
ArrayList data= new ArrayList<>();
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
data.add(resource);
}
while (cursor.moveToNext());
}
db.close();
}
return data;
}
Well, as you have it, the variable resource is scoped only to the while loop. Even if it wasn't it would constantly get overwritten on each loop iteration.
Instead, you should declare a collection higher up and Add each value to it during your while loop. You could also redefine your function to return the collection if integers.
public List<int> getIconResource(String tblName)
{
SQLiteDatabase db = this.getReadableDatabase();
List<int> myVals = new List<int>();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource, null); //null for conditions
if (cursor.moveToFirst())
{
do
{
myVals.Add(cursor.getInt(3));
}
while (cursor.moveToNext());
}
db.close();
return myVals;
}
Also, as a note... string concatenation of a SQL query is a recipe for disaster. Look up SQL Injection and best practices to avoid it before continuing further. It is worth the time to get into good habits early on.
EDIT / ADDENDUM
Unless you also limit your result set returned from your table query, you will be getting every record. The function you have here really has no practical use and would likely cause more problems than any benefits it may have. I would suggest, as an example of a more usable function that returns a specific IconResource based on the IconId:
public int getIconResource(int iconId)
{
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "select IconResource from IconTable where IconId = ?";
PreparedStatement pstmnt = db.prepareStatement(getresource);
pstrmnt.setString(1, iconId);
ResultSet rset = db.executeQuery();
int iconResource;
if (rset.next())
iconResource = rset.getInt("IconResource");
db.close();
return iconResource;
}
Of course, the above is making assumptions of your table structure.
Using the above, in your code elsewhere, you would simply call this function with the IconId and use the output however needed:
int iconResource = getIconResource(5); // returns the IconResource for IconId = 5
The above prevents any possible SQL Injection attacks by using a parameterized query and avoiding the use of dynamic concatenated strings sent to your SQL server.
You may try out the following code:
public List<Integer> getIconResource(String tblName)
{
List<Integer> list = new ArrayList<Integer>();
list.clear();
SQLiteDatabase db = this.getReadableDatabase();
String getresource = "Select * from " + tblName;
Cursor cursor = db.rawQuery(getresource,null); //null for conditions
if(cursor.moveToFirst())
{
do
{
int resource = cursor.getInt(3);
list.add(resource);
}
while (cursor.moveToNext());
}
db.close();
return list;
}
Then call this method in MainActivity and store the List in another Integer type list.
databasehelper dbhelper;
List<Integer> newList = dbhelper.getIconResource("Your tablename");
fot(int i = 0 ; i< newList.size() ; i++){
int yourValue = newList(i);
}
I have some trouble with a SQLite database with 1 table and 2 columns, column_id and word. I extended SQLiteAssetHelper as MyDatabase and made a constructor:
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
I need to check whether some string is in the database (in column word). I tried to modify the code from answer provided by Benjamin and dipali, but I used SQLiteAssetHelper and I can't get it to work. The method that I have in mind receives the string to search for as a parameter and returns a boolean if string is in the database.
public boolean someMethod(String s)
In addition, I tried to put the check on a background thread with AsyncTask because I have 60 strings to check.
TABLE_NAME and COLUMN_WORD should be self-explanatory.
public boolean someMethod(String s) {
SQLiteDatabase db = getReadableDatabase();
String[] columns = new String[] {COLUMN_WORD};
String where = COLUMN_WORD + " = ?";
String[] whereArgs = new String[] {s};
// select column_word from table where column_word = 's' limit 1;
Cursor cursor = db.query(TABLE_NAME, columns, where, whereArgs, null, null, null, "1");
if (cursor.moveToFirst()) {
return true; // a row was found
}
return false; // no row was found
}
You can do this in the background, but I don't think for a query like this it's even necessary.
EDIT
There are some improvements that should be made to the above for the sake of correctness. For one thing, the Cursor should be closed since it is no longer being used. A try-finally block will ensure this:
Cursor cursor = db.query(...);
try {
return cursor.moveToFirst();
} finally {
cursor.close();
}
However, this method doesn't need to obtain a whole `Cursor. You can write it as follows and it should be more performant:
public boolean someMethod(String s) {
SQLiteDatabase db = getReadableDatabase();
String sql = "select count(*) from " + TABLE_NAME + " where "
+ COLUMN_WORD + " = " + DatabaseUtils.sqlEscapeString(s);
SQLiteStatement statement = db.compileStatement(sql);
try {
return statement.simpleQueryForLong() > 0;
} finally {
statement.close();
}
}
You could add a catch block and return false if you think it's possible (and valid) to encounter certain exceptions like SQLiteDoneException. Also note the use of DatabaseUtils.sqlEscapeString() because s is now concatenated directly into the query string and thus we should be wary of SQL injection. (If you can guarantee that s is not malicious by the time it gets passed in as the method argument, then you could theoretically skip this, but I wouldn't.)
because of possible data leaks best solution via cursor:
Cursor cursor = null;
try {
cursor = .... some query (raw or not your choice)
return cursor.moveToNext();
} finally {
if (cursor != null) {
cursor.close();
}
}
1) From API KITKAT u can use resources try()
try (cursor = ...some query)
2) if u query against VARCHAR TYPE use '...' eg. COLUMN_NAME='string_to_search'
3) dont use moveToFirst() is used when you need to start iterating from beggining
4) avoid getCount() is expensive - it iterates over many records to count them. It doesn't return a stored variable. There may be some caching on a second call, but the first call doesn't know the answer until it is counted.
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.