I am trying to get one specific entry out of my DB with following code:
Object specificObject = myDbHelper.getObject(int id, int level);
// code in DataBaseHelper:
public Object getObject(int id, int level){
c = myDataBase.rawQuery("SELECT * FROM QUESTIONS WHERE ID =" + id + " AND LEVEL = " + level, null);
Object q = new Object();
q.setQuestion(c.getString(1));
q.setName(c.getString(2));
q.setFile(c.getInt(3));
q.setAnswer(c.getString(4));
return q;
}
The problem is this results in following error:
09-24 11:12:52.299: E/AndroidRuntime(7388): Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
Any ideas? It seems that it knows that it has a size of one (one entry?) but i don't get the index -1 requested issue...
Before accessing data from cursor you have to move first record.
c.moveToFirst()
You should do it like:
c = myDataBase.rawQuery("SELECT * FROM QUESTIONS WHERE ID =" + id + " AND LEVEL = " + level, null);
if(c.moveToFirst()) {
Object q = new Object();
q.setQuestion(c.getString(1));
q.setName(c.getString(2));
q.setFile(c.getInt(3));
q.setAnswer(c.getString(4));
return q;
}
return null;
Related
I am creating a SQLite database in android. But there is some error appearing up whenever I call the method "displayDatabase()".
Please Help!!
Here is the displayDatabase() Method:
public void displayDatabase() {
DataDbHelper mDbHelper = new DataDbHelper(this);
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] projection = {DataContract.DataEntry.COLUMN_PROJECT_NAME,
DataContract.DataEntry.COLUMN_HEAD,
DataContract.DataEntry.COLUMN_CITY,
DataContract.DataEntry.COLUMN_COST};
Cursor c = db.query(DataContract.DataEntry.TABLE_NAME,
projection,
null,
null,
null,
null,
null);
TextView textView = (TextView) findViewById(R.id.textview);
try {
//textView.setText("The database contains - " + c.getColumnCount() + "Columns containing data");
textView.setText("Hello Welcome\n");
textView.append("-" + DataContract.DataEntry._ID
+ "---" + DataContract.DataEntry.COLUMN_PROJECT_NAME
+ "---" + DataContract.DataEntry.COLUMN_HEAD
+ "---" + DataContract.DataEntry.COLUMN_CITY
+ "---" + DataContract.DataEntry.COLUMN_COST + "\n");
int currentId = c.getColumnIndex(DataContract.DataEntry._ID);
int projectNameId = c.getColumnIndex(DataContract.DataEntry.COLUMN_PROJECT_NAME);
int headId = c.getColumnIndex(DataContract.DataEntry.COLUMN_HEAD);
int cityId = c.getColumnIndex(DataContract.DataEntry.COLUMN_CITY);
int costId = c.getColumnIndex(DataContract.DataEntry.COLUMN_COST);
while (c.moveToNext()) {
int id = c.getInt(currentId);
String projectName = c.getString(projectNameId);
String head = c.getString(headId);
String city = c.getString(cityId);
String cost = c.getString(costId);
textView.append("-" + id
+ "---" + projectName
+ "---" + head
+ "---" + city
+ "---" + cost);
}
} finally {
c.close();
}
}
And here is the error appearing in the logcat :
CursorWindow: Failed to read row 0, column -1 from a CursorWindow
which has 11 rows, 4 columns. 03-15 10:00:58.359 6348-6348/?
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.student.sampledatabase, PID: 6348
java.lang.IllegalStateException: Couldn't read row 0, col -1 from
CursorWindow. Make sure the Cursor is initialized correctly before
accessing data from it.
Add this column, DataContract.DataEntry._ID, to your projection.
The Cause of the Error
The reason for the failure is that an attempt is being to get a column at offset -1, which will never exist as offsets can be from 0 to the number of columns in the cursor less 1.
The reason why -1 is being used is because that is the value returned from the
Cursor getColumnIndex method when the column name passed to the method does not exist in the cursor.
The reason why you are getting the -1 is that you have not included the column who's name is as per DataContract.DataEntry._ID resolved in the cursor so the line :-
int currentId = c.getColumnIndex(DataContract.DataEntry._ID);
results in currentId being -1
Thus the above error when the following line is executed :-
int id = c.getInt(currentId);
The Fix
One fix, would be to specify null instead of projection, this would result in all columns of the table being retrieved and is the equivalent of using SELECT * FROM .......
e.g. by using :-
Cursor c = db.query(DataContract.DataEntry.TABLE_NAME,
null,
null,
null,
null,
null,
null);
Another fix would be to change :-
String[] projection = {DataContract.DataEntry.COLUMN_PROJECT_NAME,
DataContract.DataEntry.COLUMN_HEAD,
DataContract.DataEntry.COLUMN_CITY,
DataContract.DataEntry.COLUMN_COST};
to instead be :-
String[] projection = {DataContract.DataEntry._ID,
DataContract.DataEntry.COLUMN_PROJECT_NAME,
DataContract.DataEntry.COLUMN_HEAD,
DataContract.DataEntry.COLUMN_CITY,
DataContract.DataEntry.COLUMN_COST};
Thus the column will then be included in the Cursor and the offset will be the offset of that column (0 in the case above as it is the first column in the result).
I have two method's in my SQLite Database in which i check if there is in a table certain column that is the same as a String after it i print all other columns on the same row and with the second method i check if a column from the first method equals to a data stored in a column of another table.
But i'm having issues when i check for a data that is not in the database here is an example:
TABLE CODART_BARCODE
CODART_CODART CODART_BARCODE CODART_PXC
123 1234 1
TABLE CODART_ART
DESCR_ART PVEN_ART PACQ_ART CODART_ART
PIZZ 1.50 12 123
So if in an EditText i insert 123 that equals to CODART_CODART and there is also 123 in CODART_ART from the other table i will print "PIZZ 1.50 12" but if i insert in the EditText 12356 the app crash because there is no same data in DB how can i prevent that app crash? i mean if there is no same data can i make a Toast that says "no data" or something like this but not making the app crash?
Here are the two methods from DB:
public String dbRawSearch(String id) {
StringBuilder dbString = new StringBuilder();
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = " + id;
//Cursor points to a location in your results
#SuppressLint("Recycle") Cursor c = db.rawQuery(query, null);
//Move to the first row in your results
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
db.close();
return dbString.toString();
}
// FETCH codArt from Articoli
public String dbRawArticoli(String id){
StringBuilder dbString = new StringBuilder();
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = " + id;
Cursor c = db.rawQuery(query, null);
c.moveToFirst();
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_ART")) != null) {
dbString.append(c.getString(c.getColumnIndex("DESCR_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PVEN_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PACQ_ART"))).append("\n");
}
c.moveToNext();
}
db.close();
return dbString.toString();
}
Your issue is that you are not correctly enclosing the search argument and thus if the value is non numeric then SQLite will consider that you are comparing a column, hence the no column found.
Lets say assuming you use :-
String result1 = yourdbHelper.dbRawSearch("123");
Then the resultant SQL will be :-
SELECT * FROM CODART WHERE CODART_BARCODE = 123;
That is fine as the search is looking for a number.
However if you used:-
String result1 = yourdbHelper.dbRawSearch("Fred");
Then the resultant SQL will be :-
SELECT * FROM CODART WHERE CODART_BARCODE = FRED
This would fail because FRED is non-numeric, and is therefore interpreted as saying SELECT all columns from the table CODART where the column named COADRT has the same value as the column named FRED, there is no column named FRED.
The result is that you get an error along the lines of :-
06-11 11:34:12.653 1373-1373/soanswers.soanswers E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{soanswers.soanswers/soanswers.soanswers.MainActivity}: android.database.sqlite.SQLiteException: no such column: FRED (code 1): , while compiling: SELECT * FROM CODART WHERE CODART_BARCODE = FRED
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
The Fix
The resolution is simple, and that is to enclose the argument being searched for in single quotes so that the SQL is then :-
SELECT * FROM CODART WHERE CODART_BARCODE = 'FRED'
Note that is just one example. However you will need to makes similar changes to both methods (dbRawSearch and dbRawArticoli), as shown :-
To do this you could change :-
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = " + id;
to :-
String query = "SELECT * FROM " + TABLE_CODART + " WHERE CODART_BARCODE = '" + id + "'";
and also change :-
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = " + id;
to :-
String query = "SELECT * FROM " + TABLE_ART + " WHERE CODART_ART = '" + id + "'";
Additional
However, there are SQLiteDatabase convenience methods that simplify building queries which also enclose/convert data accordingly.
One of these is the query method (as used in the following).
Rather than
moving to the first row and then
checking to see if you are then at the last row and then
using a moveToNext then going back to 2
in a do while loop, as all of the Cursor move??? methods return
true if the move could be made
otherwise false
you can simplify matters using :-
while(yourcursor.moveToNext) {
.... process the current row
}
As such the following methods could be considered
Note the 2 at the end of the method name is just to distinguish them from the originals
:-
public String dbRawSearch2(String id) {
StringBuilder dbString = new StringBuilder();
String whereclause = "CODART_BARCODE=?";
String[] whereargs = new String[]{id};
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.query(TABLE_CODART,null,whereclause,whereargs,null,null,null);
while (c.moveToNext()) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.close(); //<<<< Should always close cursors when finished with them
db.close();
return dbString.toString();
}
public String dbRawArticoli2(String id) {
StringBuilder dbString = new StringBuilder();
String whereclause = "CODART_ART=?";
String[] whereargs = new String[]{id};
SQLiteDatabase db = this.getWritableDatabase();
Cursor c= db.query(TABLE_ART,null,whereclause,whereargs,null,null,null);
while (c.moveToNext()) {
dbString.append(c.getString(c.getColumnIndex("DESCR_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PVEN_ART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("PACQ_ART"))).append("\n");
}
c.close();
db.close();
return dbString.toString();
}
you should use wether your cursor is null or not and its size
if (c != null) {
if (c.getCount() > 0) {
return "your string";
}
}
return "";// In case no record found
In blank case give proper msg to the end user.
Change this part :
//Move to the first row in your results
c.moveToFirst();
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
To :
//Move to the first row in your results
if(c!= null && c.moveToFirst())
{
//Position after the last row means the end of the results
while (!c.isAfterLast()) {
if (c.getString(c.getColumnIndex("CODART_BARCODE")) != null) {
dbString.append(c.getString(c.getColumnIndex("CODART_CODART"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_BARCODE"))).append("\n");
dbString.append(c.getString(c.getColumnIndex("CODART_PXC"))).append("\n");
}
c.moveToNext();
}
}
Explanation: In the case where there is no same data available you don't have the result set to get the string or column index from the result set.
I'm trying to implement dynamic queries in my Android app, to let the users search according to some criteria. In this case I'm trying to search simply by an integer value. Here's my attempt:
...
public String[][] listarNegocio(int idProyecto,
int minimo,
int maximo)
{
String[][] arrayDatos = null;
String[] parametros = {String.valueOf(idProyecto)};
Cursor cursor = null;
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE ? in (0, id_proyecto)", parametros);
if(cursor.getCount() > 0)
{
int i = minimo - 1;
arrayDatos = new String[maximo - minimo + 1][20];
while(cursor.moveToNext() && i < maximo)
{
// Here I fill the array with data
i = i + 1;
}
}
cursor.close();
CloseDB();
return(arrayDatos);
}
public Cursor querySQL(String sql, String[] selectionArgs)
{
Cursor oRet = null;
// Opens the database object in "write" mode.
db = oDB.getReadableDatabase();
oRet = db.rawQuery(sql, selectionArgs);
return(oRet);
}
...
I tested this query using SQLFiddle, and it should return only the rows where the column id_proyecto equals the parameter idProyecto, or every row if idProyecto equals 0. But it doesn't return anything. If I remove the WHERE clause and replace "parametros" with "null", it works fine.
Additionally, I need to search by text values, using LIKE. For example, WHERE col_name LIKE strName + '%' OR strName = ''. How should I format my parameters and the query to make it work?
You should do one query for each case. For an id that exists, do SELECT * FROM negocio WHERE id_proyecto = ?. For an id that doesn't exist (I'm assuming 0 isn't a real id), just query everything with SELECT * FROM negocio.
Code should be something like this:
if(parametros[0] != 0){
cursor = querySQL("SELECT *" +
" FROM negocio" +
" WHERE id_proyecto = ?", parametros);
} else {
cursor = querySQL("SELECT *" +
" FROM negocio", null);
}
Regarding your second question, it depends on what you're looking for, you could use LIKE '%param%' or CONTAINS for occurrences in between text, LIKE param for partial matches or just = param if you're looking an exact match.
I made a query that requests a random row from database using ID. But I have a little problem. I want it to show a message if it exists or it doesn't exist. For example my database like that:
ID - ingilizce - turkce
1 - hello - merhaba
4 - hi - selam
As you see, the second and third record don't exist. I generate a random number between 1 and 4 and I get the row that belongs to ID. So, when it generates a number like 2 or 3, it will generate a new random number.
My code is here:
public void kelimeUret() {
SQLiteDatabase db = kelimeler.getReadableDatabase();
rastgele = new Random();
Cursor kayit = db.rawQuery("SELECT count(*) FROM kelimeler", null);
kayit.moveToFirst();
int max = Integer.parseInt(kayit.getString(0));
int min = 1;
int rastgeleKayit = rastgele.nextInt(max - min + 1) + min;
Cursor kayit3 = db.rawQuery("SELECT * FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit3.moveToFirst();
int kayitSayisi = kayit3.getCount();
if (kayitSayisi<1) {
//Toast.makeText(getApplicationContext(), "bu kayıt yok", Toast.LENGTH_SHORT).show();
//kelimeUret();
// I COULDN'T DO HERE !
} else {
Cursor kayit2 = db.rawQuery("SELECT ingilizce FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit2.moveToFirst();
String sonuc = kayit2.getString(0);
olusturulanKelime = sonuc;
kelime = (TextView) findViewById(R.id.kelime);
kelime.setText(sonuc);
}
Thanks for your responds...
Cursor kayit3 = db.rawQuery("SELECT * FROM kelimeler WHERE id=" + rastgeleKayit, null);
kayit3.moveToFirst();
kayit3.getCount(); will return the number of records returned by the query. If there are no records, then it does not exist. If it returns more than 1 record, then the record exist.
Hope this helps
I get this error on a device, while it works good on another device. Here is the error :
Caused by: android.database.sqlite.SQLiteException: not an error
at android.database.sqlite.SQLiteQuery.nativeFillWindow(Native Method)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:86)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156)
at com.Orange.MakeVisits.Themes.onCreate(Themes.java:162)
I execute a query and at the line that checks if the Cursor is null, I get this error. Here is my code :
String stmtGetThemes = "SELECT * FROM pr_fields_descriptor a "
+ "inner join pr_fields_starring b on a.id_fields_descriptor = b.fields_descriptor_id "
+ "where b.starring_id = '"+pos_starring_id+"' and a.theme_id='"+themes_ids[m]+"' order by form_rank";
Cursor getThemesCursor1 = db.databaseQuery(stmtGetThemes);
if (getThemesCursor1!=null && getThemesCursor1.getCount()>0){
//----
}
and databasequery is this method (is defined in the class that extends SQLiteOpenHelper):
public Cursor databaseQuery(String stmt) {
Cursor cursor = db.rawQuery(stmt, null);
return cursor;
}
Any idea what can cause this error ? The statement is not good ? Why it works on others devices?
Any idea is welcome. Thanks in advace.
String stmtGetThemes = "SELECT * FROM pr_fields_descriptor a "
+ "inner join pr_fields_starring b on a.id_fields_descriptor = b.fields_descriptor_id "
+ "where b.starring_id = '"+pos_starring_id+"' and a.theme_id='"+themes_ids[m]+"' order by form_rank";
Do not terminate this query by ";".
Don't Pass array Type Paramters in Query, sometimes it won't work
int themes_id = themes_ids[m];
String stmtGetThemes = "SELECT * FROM pr_fields_descriptor a inner join pr_fields_starring b on a.id_fields_descriptor = b.fields_descriptor_id where b.starring_id = '"+pos_starring_id+"' AND a.theme_id = '"+themes_id+"' ORDER BY form_rank";
Cursor getThemesCursor1 = db.databaseQuery(stmtGetThemes);
if (getThemesCursor1 != null && getThemesCursor1.getCount() != 0){
//----
}