Specific query error - SQLite Android - java

my problem is with very specific query. My SQLite datbase is only 1 table with 11 entries. It creates just fine, but upon execution of this piece of code it crashes. When I change the query to simply:
SELECT * FROM Items
Then it works fine, but I need more narrow results, therefore I modify with the "WHERE" clause. But then it crashes and the application stops. If I comment out the Cursor... it runs fine.
public int findPictureNumber(String itemtitle) {
String query = "SELECT nr_of_pics FROM Items WHERE ItemTitle = \"" + itemtitle + "\"";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
...
}
Where is the error? I can't seem to find it even after narrowing it down to those lines of code.
EDIT:
This is a method for adding an item to a database.
public void newItemFuro () {
MyDBHandler dbHandler = new MyDBHandler(this, null, null, 1);
String title = "Furo";
String author = "Fernando Brizio";//í
String category = "Decoracao";//çã
int date = 2012;
String type = "Taca";//ç
String country = "Portugal";
String colour = "Castanho/Cortica";//ç
String material = "Castanho/Cortica";//ç
boolean isFavourite = false;
String imgres = "furoo";
int nr_of_pics = 3;
Item item = new Item(title, author, category, date, type, country, colour, material, isFavourite, imgres, nr_of_pics);
dbHandler.addItem(item);
}
//helper for types
public static final String VARCHAR_TYPE = " VARCHAR(50)";
public static final String BOOL_TYPE = " BOOLEAN";
public static final String INT_TYPE = " INTEGER";
Here it creates the table:
public void onCreate(SQLiteDatabase db) {
String CREATE_ITEMS_TABLE = "CREATE TABLE " + TABLE_ITEMS +
"("
+ COLUMN_ENTRY_ID + INT_TYPE +" PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_TITLE + VARCHAR_TYPE + ","
+ COLUMN_AUTHOR + VARCHAR_TYPE + ","
+ COLUMN_CATEGORY + VARCHAR_TYPE + ","
+ COLUMN_DATE + INT_TYPE + ","
+ COLUMN_TYPE + VARCHAR_TYPE + ","
+ COLUMN_COUNTRY + VARCHAR_TYPE + ","
+ COLUMN_COLOUR + VARCHAR_TYPE + ","
+ COLUMN_MATERIAL + VARCHAR_TYPE + ","
+ COLUMN_FAVOURITE + BOOL_TYPE + ","
+ COLUMN_IMGRES + VARCHAR_TYPE + ","
+ COLUMN_NUMBER_OF_PICS + INT_TYPE +
")";
db.execSQL(CREATE_ITEMS_TABLE);
}
Adding item:
public void addItem(Item item) {
ContentValues values = new ContentValues();
values.put(COLUMN_TITLE, item.getItemTitle());
values.put(COLUMN_AUTHOR, item.getAuthor());
values.put(COLUMN_CATEGORY, item.getCategory());
values.put(COLUMN_DATE, item.getDate());
values.put(COLUMN_TYPE, item.getType());
values.put(COLUMN_COUNTRY, item.getCountry());
values.put(COLUMN_COLOUR, item.getColour());
values.put(COLUMN_MATERIAL, item.getMaterial());
values.put(COLUMN_FAVOURITE, item.getFavourite());
values.put(COLUMN_IMGRES, item.getImgres());
values.put(COLUMN_NUMBER_OF_PICS, item.getNumberOfPics());
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_ITEMS, null, values);
db.close();
}
Here full function for searching nr_of_pics:
public int findPictureNumber(String itemtitle) {
String query = "SELECT nr_of_pics FROM Items WHERE ItemTitle = '" + itemtitle + "'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
int PicsNumber=0;
if (cursor.moveToFirst()) {
cursor.moveToFirst();
PicsNumber=Integer.parseInt(cursor.getString(0));
cursor.close();
return PicsNumber;
} else {
//wtf?
}
db.close();
return 0;
}
And the errors say as follows:
(1) table Items has no column named imgres
Error inserting colour=Castanho/Cortiça author=Fernando Brízio
imgres=furo category=Decoração title=Furo type=Taça date=2012
nr_of_pics=3 material=Castanho/Cortiça is_favourite=false
country=Portugal
android.database.sqlite.SQLiteException: table Items has no column named imgres (code 1): , while
compiling: INSERT INTO
Items(colour,author,imgres,category,title,type,date,nr_of_pics,material,is_favourite,country)
VALUES (?,?,?,?,?,?,?,?,?,?,?)

You do not give any exception but I think you have error in your SQL. You need to use ' instead of ".
Change your query as below.
String query = "SELECT nr_of_pics FROM Items WHERE ItemTitle = '" + itemtitle + "'";

It is clear that you don't have any column that named "imgres"!
You should modify your query
"INSERT INTO Items(colour,author,imgres,category,title,type,date,nr_of_pics,material,is_favourite,country)
VALUES (?,?,?,?,?,?,?,?,?,?,?)"

Related

Android studio SQL - How to return data in a string array

I have an SQL method here. I would like to return the data in a String[] array.
How do I do that exactly?
Thank you!
public String[] getLikedSongs() {
SQLiteDatabase db = this.getReadableDatabase();
String[] LikeSong;
Cursor cursor = db.rawQuery(" SELECT " + COL_4 + " FROM " + Table_Name + " WHERE " + COL_4 + " IS NOT NULL", null);
while (cursor.moveToNext()) {
String note = cursor.getString(0);
}
cursor.close();
db.close();
return LikeSong;
}
You must define the array's length and this can be done only after the Cursor fetches all the rows. Then set its length to the nimber of rows of the Cursor.
Then inside the while loop set the items of the array:
public String[] getLikedSongs() {
String[] LikeSong = null;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT " + COL_4 + " FROM " + Table_Name + " WHERE " + COL_4 + " IS NOT NULL", null);
if (cursor.getCount() > 0) {
LikeSong = new String[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
LikeSong[i] = cursor.getString(0);
i++;
}
}
cursor.close();
db.close();
return LikeSong;
}

SQLite Comparing tables in Android

Is there any method to compare tables (with the same properties of course) and return true if they are the same and false if not? Thanks.
Not directly but it is realtively easy.
That is sqlite stores the SQL used to define the tables in the table sqlite_master (the schema).
For the simplest comparision of SQL to SQL (for column definitions) then you could use the following SQL:-
WITH tablenames(table1,table2) AS (SELECT 'table1' /*<<<<< change accordingly */,'table2' /*<<<<< change accordingly*/)
SELECT
COALESCE(
(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table1 FROM tablenames)) =
(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table2 FROM tablenames))
,0)
;
In Android this could be done using (within a database helper ) :-
public boolean compareTable(String table1, String table2) {
SQLiteDatabase db = this.getWritableDatabase();
String result_column = "result";
boolean rv = false;
Cursor csr = db.rawQuery("WITH tablenames(table1,table2) AS (SELECT ? ,? )" +
"SELECT " +
"COALESCE(" +
"(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table1 FROM tablenames)) =" +
"(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table2 FROM tablenames))" +
",0) " +
"AS " + result_column +
";",new String[]{table1,table2});
if (csr.moveToFirst()) {
rv = (csr.getInt(csr.getColumnIndex(result_column)) > 0);
}
csr.close();
return rv;
}
Note this will consider the slightest difference in the SQL as failing the comparison
Example
The Database Helper DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TABLE = "htmlstore";
public static final String IDCOLUMN = BaseColumns._ID;
public static final String HTMLCOLUMN = "html";
public static final String TABLE2 = "otherstore";
public static final String TABLE3 = "storeother";
SQLiteDatabase db;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
db = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
String crt_htmlstore_table = "CREATE TABLE IF NOT EXISTS " + TABLE + "(" +
IDCOLUMN + " INTEGER PRIMARY KEY," +
HTMLCOLUMN + " TEXT" +
")";
db.execSQL(crt_htmlstore_table);
String crt_otherstore_table = "CREATE TABLE IF NOT EXISTS " + TABLE2 + "(" +
IDCOLUMN + " INTEGER PRIMARY KEY," +
HTMLCOLUMN + " TEXT" +
")";
db.execSQL(crt_otherstore_table);
String crt_storeother_table = "CREATE TABLE IF NOT EXISTS " + TABLE3 + "(" +
HTMLCOLUMN + " TEXT, " +
IDCOLUMN + " INTEGER, " +
" PRIMARY KEY(" + IDCOLUMN + ")" +
")";
db.execSQL(crt_storeother_table);
}
public long insert(String html) {
ContentValues cv = new ContentValues();
cv.put(HTMLCOLUMN,html);
return db.insert(TABLE,null,cv);
}
public String getHTML(long id) {
String rv = "";
Cursor csr = db.query(TABLE,new String[]{HTMLCOLUMN},IDCOLUMN+"=?",new String[]{String.valueOf(id)},null,null,null);
if (csr.moveToFirst()) {
rv = csr.getString(csr.getColumnIndex(HTMLCOLUMN));
}
csr.close();
return rv;
}
public boolean compareTable(String table1, String table2) {
SQLiteDatabase db = this.getWritableDatabase();
String result_column = "result";
boolean rv = false;
Cursor csr = db.rawQuery("WITH tablenames(table1,table2) AS (SELECT ? ,? )" +
"SELECT " +
"COALESCE(" +
"(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table1 FROM tablenames)) =" +
"(SELECT substr(sql,instr(sql,'(')) FROM sqlite_master WHERE name = (SELECT table2 FROM tablenames))" +
",0) " +
"AS " + result_column +
";",new String[]{table1,table2});
if (csr.moveToFirst()) {
rv = (csr.getInt(csr.getColumnIndex(result_column)) > 0);
}
csr.close();
return rv;
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Note that effectively the 3 tables are all the same (BUT the 3rd table differs in the SQL used to generate the column definitions and will thus be considered different)
COALESCE is used to convert a null (no such table(s) in sqlite_master) to 0 (false)
The invoking code MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DatabaseHelper databaseHelper = new DatabaseHelper(this);
Log.d("TABLECOMPARE"," Result = " + String.valueOf(databaseHelper.compareTable(DatabaseHelper.TABLE,DatabaseHelper.TABLE2)));
Log.d("TABLECOMPARE"," Result = " + String.valueOf(databaseHelper.compareTable(DatabaseHelper.TABLE2,DatabaseHelper.TABLE3)));
Log.d("TABLECOMPARE"," Result = " + String.valueOf(databaseHelper.compareTable(DatabaseHelper.TABLE,DatabaseHelper.TABLE3)));
Log.d("TABLECOMPARE"," Result = " + String.valueOf(databaseHelper.compareTable(DatabaseHelper.TABLE,DatabaseHelper.TABLE)));
}
}
Result :-
2020-01-14 07:23:29.624 D/TABLECOMPARE: Result = true
2020-01-14 07:23:29.625 D/TABLECOMPARE: Result = false
2020-01-14 07:23:29.625 D/TABLECOMPARE: Result = false
2020-01-14 07:23:29.626 D/TABLECOMPARE: Result = true
i.e.
Table1 and Table2 are considered the same
Table2 and Table3 are considered different
Table1 and Table3 are considered different
Table1 is considered the same as table 1.

How to get other column with onItemClickListener in ListView

I am working on a Shopping list where you can click on the item in the ListView and a dialog comes up. There you can modify the product name. It works fine, but now i am trying to add details.
Adding to database already works. It is in the third column but now I cant get it out with the onItemClickListener.
Get Data from the second column works fine, so the the product is working fine with ItemOnClick.
I already tried a couple of codes but didnt find a solution.
OnItemClick:
lvProducts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
//DB*********************************
String name = parent.getItemAtPosition(position).toString();
Log.d(TAG, "onItemClick: You Clicked on " + name);
Cursor data = myDB.getItemID(name);
int itemID = -1;
while (data.moveToNext()){
itemID = data.getInt(0);
}
if (itemID > -1){
Log.d(TAG, "onItemClick: The ID is " + itemID);
Intent editScreenIntent = new Intent();
editScreenIntent.putExtra("id",itemID);
editScreenIntent.putExtra("name",name);
selectedID = editScreenIntent.getIntExtra("id",-1);
selectedName = editScreenIntent.getStringExtra("name");
}
showInputBox(arrayList.get(position), position);
} catch (Exception e) {
Toast.makeText(ShoppingActivity.this, "Error#666", Toast.LENGTH_SHORT).show();
}
}
});
DatabaseHelper:
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME = "myList_data";
public static final String COL1 = "ID";
public static final String COL2 = "ITEM1";
public static final String COL3 = "ITEM2";
public DatabaseHelper(Context context){
super(context, TABLE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, " + COL2 + " TEXT, " + COL3 + " TEXT )";
db.execSQL(createTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+ TABLE_NAME);
onCreate(db);
}
public boolean addData(String item, String detail){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2,item);
contentValues.put(COL3, detail);
long result = db.insert(TABLE_NAME,null,contentValues);
if (result == -1){
return false;
}else {
return true;
}
}
public Cursor getData(){
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_NAME;
Cursor data = db.rawQuery(query, null);
return data;
}
public Cursor getItemID(String name){
SQLiteDatabase db = this.getWritableDatabase();
//String query = "SELECT "+ COL1 + " FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = db.rawQuery("SELECT * FROM " + TABLE_NAME,null);
//Cursor data = db.rawQuery(query, null);
return data;
}
/**
* Updates the name field
* #param newName
* #param id
* #param oldName
*/
public void updateName(String newName,int id,String oldName){
SQLiteDatabase db = this.getWritableDatabase();
String query = "UPDATE " + TABLE_NAME + " SET " + COL2 + " = '" + newName + "' WHERE " + COL1 + " = '" + id + "'" + " AND " + COL2 + " = '" + oldName + "'";
db.execSQL(query);
}
public void deleteName(int id, String name){
SQLiteDatabase db = this.getWritableDatabase();
String query = "DELETE FROM " + TABLE_NAME + " WHERE " + COL1 + " = '" + id + "'" + " AND " + COL2 + " = '" + name + "'";
db.execSQL(query);
}
public void deleteAll(){
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME,null,null);
String query =("DELETE FROM " + TABLE_NAME);
db.execSQL(query);
}
}
Try :-
int itemID = -1;
String item3 = ""; //<<<<<<<<<< ADDED
while (data.moveToNext()){
itemID = data.getInt(0);
item3 = data.getString(data.getColumnIndex(DatabaseHelper.COL3)); //<<<<<<<<<< ADDED
}
Note using getColumnIndex and the column name is more flexible and less prone to mis-calculation of offsets. You may wish to consider changing itemID = data.getInt(0); to itemID = data.getInt(data.getColumnIndex(DatabaseHelper.COL1));
Your getItemId method will, as it stands get all rows not just the row that has the name. You may wish to change from :-
public Cursor getItemID(String name){
SQLiteDatabase db = this.getWritableDatabase();
//String query = "SELECT "+ COL1 + " FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = db.rawQuery("SELECT * FROM " + TABLE_NAME,null);
//Cursor data = db.rawQuery(query, null);
return data;
}
to :-
public Cursor getItemID(String name){
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_NAME,null,COL2+"=?",new String[]{name},null,null,null);
}
Note the above is in-principle code. It has not been tested or run and may therefore have some errors.

Paste comma separated list into EditText and store in SQLite TABLE on multiple rows

I'm wondering how to paste a comma separated list (test1,test2,test3,test4) in an EditText field and on clicking a button have it store in my SQLite Database Table with each one on it's own row. This would be ideal so that people with a big list (50-100) can mass insert data. Right now I have it to were it will insert a single name into my Table.
DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DatabaseHelper";
private static final String TABLE_NAME = "hashtag_table";
private static final String COL1 = "ID";
private static final String COL2 = "name";
#Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, " + COL2 +" TEXT)";
db.execSQL(createTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP IF TABLE EXISTS " + TABLE_NAME);
onCreate(db);
}
public DatabaseHelper(Context context) {
super(context, TABLE_NAME, null, 1);
}
/**
* Add data to the table
* #param item
* #return
*/
public boolean addData(String item) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL2, item);
Log.d(TAG, "addData: Adding " + item + " to " + TABLE_NAME);
long result = db.insert(TABLE_NAME, null, contentValues);
if (result == -1) {
return false;
} else {
return true;
}
}
/**
* Gets the data from the table
* #return
*/
public Cursor getData() {
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT * FROM " + TABLE_NAME;
Cursor data = db.rawQuery(query, null);
return data;
}
/**
* Gets the ID from the table
* #param name
* #return
*/
public Cursor getItemID(String name) {
SQLiteDatabase db = this.getWritableDatabase();
String query = "SELECT " + COL1 + " FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = db.rawQuery(query,null);
return data;
}
/**
* Updates the name from the table
* #param newName
* #param id
* #param oldName
*/
public void updateName(String newName, int id, String oldName) {
SQLiteDatabase db = this.getWritableDatabase();
String query = "UPDATE " + TABLE_NAME + " SET " + COL2 + " = '" + newName + "' WHERE " + COL1 + " = '" + id + "'" + " AND " + COL2 + " = '" + oldName + "'";
Log.d(TAG, "updateName: query: " + query);
Log.d(TAG, "updateName: setting name to " + newName);
db.execSQL(query);
}
/**
* Deletes the name from the table
* #param id
* #param name
*/
public void deleteName(int id, String name) {
SQLiteDatabase db = this.getWritableDatabase();
String query = "DELETE FROM " + TABLE_NAME + " WHERE " + COL1 + " = '" + id + "'" + " AND " + COL2 + " = '" + name + "'";
Log.d(TAG, "deleteName: query: " + query);
Log.d(TAG, "deleteName: Deleting " + name + " from database.");
db.execSQL(query);
db.execSQL("UPDATE SQLITE_SEQUENCE SET seq = 0 WHERE NAME = '"+TABLE_NAME+"'");
}
}
ListView.java (where the editText and button is right now)
//Adds new hashtag to list and prompts if nothing is entered
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newEntry = editText.getText().toString();
if (editText.length() != 0) {
addData(newEntry);
editText.setText("");
} else {
toastMessage("you must put something in the text field");
}
}
});
populateListView();
}
/**
* Adds new data into the Database
* #param newEntry
*/
public void addData(String newEntry) {
boolean insertData = mDatabaseHelper.addData(newEntry);
if (insertData) {
toastMessage("Successfully inserted");
recreate();
} else {
toastMessage("Whoops, something went wrong");
}
}
The following is a pretty basic replacement for the addData that uses the String's split method to break the string into comma separated values and insert them :-
/**
* Add data to the table
*
* #param item
* #return
*/
public boolean addData(String item) {
String[] splitdata = item.split(","); //<<<<<<<<<< split the input string
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
boolean result = true;
db.beginTransaction(); //<<<<<<<<<< prepare to do in a single transaction
// Loop through each string inserting an entry into the database
for (String s : splitdata) {
contentValues.clear(); //<<<<<<<<<< clear any existing values to be safe
contentValues.put(COL2, s);
if (db.insert(TABLE_NAME, null, contentValues) < 1) {
result = false;
}
}
if (result) {
db.setTransactionSuccessful(); //<<<<<<<<<< only set the transaction successful if all inserts worked
}
db.endTransaction();
return result;
}
Note that this will roll back all inserts if there are any failed inserts and additionally return a false.
The above code is in principle code, it hasn't been tested or run and may therefore contains some errors.

Android SQLLiteDataBase cursor returning 0 rows

For the life of me, I can't get the cursor to return any data. I've verified that their is data in the database and my insertions are working. The official error is:
CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
Top level declarations:
private DatabaseHelper DBHelper;
private SQLiteDatabase db;
public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
this.db = this.DBHelper.getWritableDatabase();
}
My function:
public String getRandomEntry()
{
int rand;
Random random = new Random();
int numEntries = (int)this.getCount();
if(numEntries == 0)
return "ERROR: Database is empty.";
rand = random.nextInt(numEntries);
Cursor cursor = DBHelper.getWritableDatabase().rawQuery(
"SELECT * FROM " + DATABASE_TABLE
+ " WHERE " + COLUMN_A + " = " + 0, null);
Log.i("numEntries", Integer.toString(numEntries));
Log.i("rand", Integer.toString(rand));
Log.i("cursor", Integer.toString(cursor.getCount()));
cursor.moveToFirst();
return cursor.getString(0);
}
I've also tried grabbing the cursor as such:
Cursor cursor = db.rawQuery(
"SELECT * FROM " + DATABASE_TABLE
+ " WHERE " + COLUMN_A + " = " + 0, null);
Please give me your thoughts! Thank you!!
Nothing seems random here at all. It appears that you are looking for column_a with a value of 0 every time.
I would assume that column_a has nothing with a value of 0.
First of all try to query this way:
String args[] = new String[]{"0"};
Cursor cursor = db.rawQuery(
"SELECT * FROM " + DATABASE_TABLE + " WHERE " + COLUMN_A + " = ?", args);
If this not helps check your db with external tool if you query return rows there.

Categories

Resources