Android - sqlite in clause using string values from arraylist? - java

public void DBSearchCategory(String tableName) {
// 1st way
String inClause = s1.ListViewCategory.toString();
inClause = inClause.replace("[", "(");
inClause = inClause.replace("]", ")");
// Cursor cursor = database.rawQuery("SELECT CATEGORY FROM " + tableName
// + " WHERE CATEGORY NOT IN " + inClause
// + " ORDER BY RANDOM() LIMIT 1 ", null);
// 2nd way
try {
StringBuilder sb = new StringBuilder("");
for (String param : s1.ListViewCategory) {
sb.append(",").append('"').append(param).append('"');
}
params = sb.toString().substring(1);
Log.v("Tag", "params value is " + params);
} catch (StringIndexOutOfBoundsException e) {
}
Cursor cursor = database.rawQuery("SELECT CATEGORY FROM " + tableName
+ " WHERE CATEGORY NOT IN (?) "
+ " ORDER BY RANDOM() LIMIT 1 ", new String[]{params});
while (cursor.moveToNext()) {
category = cursor.getString(cursor.getColumnIndex("CATEGORY"));
s1.keyCategory = category;
}
cursor.close();
}
s1.ListViewCategory is a String type ArrayList in Singleton class s1, and it has values of categories: "game","country","city","subway","actor","pet" // In Database there are total 33 categories, and I want to exclude these 6 categories that are in s1.ListViewCategory
In rawQuery, I want to exclude categories that are in s1.ListViewCategory, so I tried 2 ways of cursor refering to these 2 stackoverflow questions:
Android - sqlite in clause using string values from array?
///Android - sqlite in clause using values from array
I used WHERE and NOT IN statement to exclude these 6 categories
When I tried 2nd way cursor, I got no error. However, the Sql query did not work. It had to exclude categories that are in String[params], but it did not work. So I used log to see what param is and I got this
2020-01-09 09:16:47.233 8978-8978/com.kj.word V/Tag: params value is
"game","country","city","subway","actor","pet"
When I tried 1st Cursor Category, I got error logcat:
Error Code : 1 (SQLITE_ERROR)
Caused By : SQL(query) error or missing database.
(no such column: game (code 1): , while compiling: SELECT CATEGORY FROM KeyWordDB WHERE CATEGORY
NOT IN (game, country, city, subway, actor, pet) ORDER BY RANDOM() LIMIT 1)
#################################################################
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1008)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:573)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:59)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLite
I confirmed that there is a database, so I guess it is probably sql query problem ...
So my question is How can I fix 1st or 2nd cursor to exclude categories that are in s1.ListViewCateogry?
I've searched real hard, but I wasn't able to find answer... Ill be real grateful, if someone answers this question

Change the double quotes with single quotes inside the loop that constructs the comma delimited list:
for (String param : s1.ListViewCategory) {
sb.append(",").append("'").append(param).append("'");
}
params = sb.toString().substring(1);
This code constructs a list like:
'game', 'country', 'city', 'subway', 'actor', 'pet'
If you use it as a parameter in the rawQuery() method then this list will be treated as a string literal and not a list of values.
So do this instead:
String sql = "SELECT CATEGORY FROM " + tableName
+ " WHERE CATEGORY NOT IN (?) "
+ " ORDER BY RANDOM() LIMIT 1 ";
sql = sql.replace("?", params);
Cursor cursor = database.rawQuery(sql, null);
Note that this method is prone to sql injection.
Another way is to create a list of ? placeholders instead of 1 placeholder and pass the list of values as an array of strings like this:
for (String param : s1.ListViewCategory) {
sb.append(",?");
}
String[] array = ListViewCategory.toArray(new String[s1.ListViewCategory.size()]);
params = sb.toString().substring(1);
String sql = "SELECT CATEGORY FROM " + tableName
+ " WHERE CATEGORY NOT IN (#) "
+ " ORDER BY RANDOM() LIMIT 1 ";
sql = sql.replace("#", params);
Cursor cursor = database.rawQuery(sql, array);

Related

error occur when try to SELECT in sqlite android

so i recently learn to write a code in android using sqlite and i try to select data from sqlite but this error occur
ive tried some suggestion from the internet and read my book but i didnt solve my problem
public Penyakit getPenyakit1(String namaGejal){
SQLiteDatabase db = this.getReadableDatabase();
String query = "SELECT idPen FROM " + TABLE_CONTACTS + " WHERE " +
namapen + " =\"" + namaGejal + "\"";
Cursor cursor = db.rawQuery(query,null);
Penyakit penyakit = new Penyakit();
if(cursor.moveToFirst()){
cursor.moveToFirst();
penyakit.set_nomber(Integer.parseInt(cursor.getColumnName(0)));
penyakit.set_namaPen(cursor.getColumnName(1));
penyakit.set_idPenyakit(Integer.parseInt(cursor.getColumnName(2)));
penyakit.set_namGej(cursor.getColumnName(3));
penyakit.set_idGejala(Integer.parseInt(cursor.getColumnName(4)));
cursor.close();
} else {
penyakit=null;
}
return penyakit;
}
this is logcat
Process: com.example.lordbramasta.pakar, PID: 18914
java.lang.NumberFormatException: For input string: "idPen"
at java.lang.Integer.parseInt(Integer.java:615)
at java.lang.Integer.parseInt(Integer.java:650)
at com.example.lordbramasta.pakar.DBAdapter.getPenyakit1(DBAdapter.java:79)
i expected the value of idPen get selected , thank you
Your problem is this line:
penyakit.set_nomber(Integer.parseInt(cursor.getColumnName(0)));
cursor.getColumnName(0) returns idPen as this is the name of the only column returned by your query:
SELECT idPen FROM ....
and your code is trying to cast the string "idPen" to an integer.
So getColumnName() returns the name of the column at a specified index and not the value of the column.
You should do
penyakit.set_nomber(Integer.parseInt(cursor.getString(0)));
or if the data type of the column idPen is INTEGER then:
penyakit.set_nomber(cursor.getInt(0));
Also don't try to get any other columns because your query returns only 1.
Note: remove that cursor.moveToFirst(); inside the if block because it is already executed.
Probably you need to use a ' instead of ". So, change the query to the following:
String query = "SELECT idPen FROM " + TABLE_CONTACTS + " WHERE " +
namapen + " =\'" + namaGejal + "\'";
I'm suggesting you to use SQLiteDatabase.query() instead rawQuery like this:
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
"idPen"
};
// Filter results WHERE "namapen" = 'namaGejal'
String selection = "namapen" + " = ?";
String[] selectionArgs = { namaGejal };
// How you want the results sorted in the resulting Cursor
String sortOrder = null; // null for default order
Cursor cursor = db.query(
TABLE_CONTACTS, // The table to query
projection, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
// do something with the cursor
Please take a look Read information from a database
If you want to get all columns data from your TABLE_CONTACTS use SELECT * FROM

SQL error or missing database (near “?”: syntax error)

private static final String QUERY = "SELECT * FROM " + TABLE_SONG_DETAILS + " WHERE " + TABLE_SONG_DETAILS + "." + "artist" + "=? ORDER BY track ?";
private PreparedStatement queryAllSongsInfo = conn.prepareStatement(QUERY);
// the user inputs the artist_name and ORDER
queryAllSongsInfo.setString(1, artist_name);
if (order == ORDER_BY_DESC) {
queryAllSongsInfo.setString(2, "DESC");
} else {
queryAllSongsInfo.setString(2, "ASC");
}
Shows the error: SQL error or missing database (near “?”: syntax error)
If i only include the first placeholder then it works fine.
queryAllSongsInfo.setString(1, artist_name);
Why cant i use multiple placeholders ?? Why the second placeholder doesn't consider the second input from user?
You can use placeholders only for column values. You can't use them for table names, column names or (as you tried in this example) reserved words.
You can create two SQL strings, one for ascending order and the other for descending order:
private static final String QUERY_ASC = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track ASC";
private static final String QUERY_DESC = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track DESC";
private PreparedStatement queryAllSongsInfo = conn.prepareStatement(order==ORDER_BY_DESC?QUERY_DESC:QUERY_ASC);
// the user inputs the artist_name and ORDER
queryAllSongsInfo.setString(1, artist_name);
No when you use :
queryAllSongsInfo.setString(2, "DESC");
This will put DESC or ASC keywords between two quotes like this ORDER BY track 'DESC' and this is not correct.
Instead use concatenation directly with the query for example :
String QUERY = "SELECT * FROM "+TABLE_SONG_DETAILS +" WHERE "+TABLE_SONG_DETAILS+"."+"artist"+"=? ORDER BY track ";
if(order==ORDER_BY_DESC) {
QUERY += "DESC";
}else {
QUERY += "ASC";
}
PreparedStatement queryAllSongsInfo = conn.prepareStatement(QUERY);
queryAllSongsInfo.setString(1, artist_name);

How to do a SQLiteDatabase contains search in Android

As far as I'm aware of the character ? is used as a placeholder and it will be replaced with the value that you pass in the whereArgs String array.
This is my code for the query:
String whereClause = null;
String[] whereArgs = null;
if (search != "") {
whereClause = InventoryEntry.COLUMN_INVENTORY_ITEM_NAME +
" CONTAINS(" + InventoryEntry.COLUMN_INVENTORY_ITEM_NAME + ",?)";
whereArgs = new String[]{search};
}
Cursor cursor = db.query(InventoryEntry.TABLE_NAME,
null,
whereClause,
whereArgs,
null,
null,
orderBy
);
When I go to execute the query I get the following error:
android.database.sqlite.SQLiteException: near "CONTAINS": syntax error (code 1): , while compiling: SELECT * FROM items WHERE itemName CONTAINS(itemName,?) ORDER BY date ASC
What do I need to change so that my query will be in the form of:
SELECT * FROM items WHERE itemName CONTAINS(itemName,`search`);
Also, is it proper practice to use CONTAINS over LIKE?
Thank you!
SQLite does not have a CONTAINS keyword.
You could do something LIKE this:
whereClause = InventoryEntry.COLUMN_INVENTORY_ITEM_NAME +
" LIKE " + InventoryEntry.COLUMN_INVENTORY_ITEM_NAME +
" OR " + InventoryEntry.COLUMN_INVENTORY_ITEM_NAME +
" LIKE ?";
whereArgs = new String[]{search};
Also, do not compare strings with the != operator, use the equals() method::
if (!"".equals(search)) {
// ...
}
Or check the length of the String:
if (search != null && search.length() > 0) {
// ...
}
The != operator checks for reference equality when comparing objects.

Android / Java: How to get last row value in sqlite?

Hello I am using a sqlite database in my android application, and I have question:
I am trying to get the last value text(thats the collumn) from the last row from the table TABLE_XYZ... but it does not work.. i am using the following code...what am I doing wrong?
another question is, how can I return two values instead of only one, when I want to get several values from the last row like column text and message?
private static final String KEY_MESSAGE = "message";
private static final String KEY_TEXT = "text";
...
String selectQuery= "SELECT * FROM " + TABLE_XYZ+" ORDER BY column DESC LIMIT 1";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
cursor.close();
return cursor.getString( cursor.getColumnIndex(KEY_TEXT) );
EDIT:
i hade some errors in my Query,, i fixed it, but still have errors:
String selectQuery= "SELECT * FROM " + TABLE_XYZ + " ORDER BY " + KEY_TEXT+ " DESC LIMIT 1";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
String str = cursor.getString( cursor.getColumnIndex(KEY_TEXT );
cursor.close();
return str;
while debugging I can see that cursor does have the right values inside... but when i try to get the column value with this command "cursor.getString( cursor.getColumnIndex(KEY_TEXT );"... it does not work...
you are closing cursor before getting it's value
try this :
String selectQuery= "SELECT * FROM " + TABLE_XYZ+" ORDER BY column DESC LIMIT 1";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
String str = "";
if(cursor.moveToFirst())
str = cursor.getString( cursor.getColumnIndex(KEY_TEXT) );
cursor.close();
return str;
From the android documentation: http://developer.android.com/reference/android/database/Cursor.html
abstract void close()
Closes the Cursor, releasing all of its resources and making it completely invalid.
You are closing the cursor before returningthe string.
Like #whatever5599451 said you should not close the cursor before you get value. Also try a query like this:
String selectQuery = "SELECT column FROM " + TABLE_XYZ +
" ORDER BY column DESC LIMIT 1";
You can specify the columns also specify to return only 1 row.
This will bring back only the column you are ordering by you can also specify more columns example:
String selectQuery = "SELECT column, column2, column3 FROM " + TABLE_XYZ +
" ORDER BY column DESC LIMIT 1";
* means select all columns
to get the last column, use the name of the column instead of " * " (* means all, all the fields)
#Steve: do this:
String selectQuery= "SELECT " + KEY_TEXT + " FROM " + TABLE_XYZ + " ORDER BY " + KEY_TEXT+ " DESC LIMIT 1";
then you get just one String with the last record containing just the right column

Multiple updates in one sql query

I have a table in H2 DB
Order
--------
id (key)
MarketId1
MarketId2
MarketId3
ListName1
ListName2
ListName3
From XML I'm getting list of ListOrder
public final class ListOrder
{
public long listId;
public String Name;
}
So I have 3 prepared statements
"UPDATE Order set " + ListName1 + " = ? WHERE " + MarketId1 + " = ?"
"UPDATE Order set " + ListName2 + " = ? WHERE " + MarketId2 + " = ?"
"UPDATE Order set " + ListName3 + " = ? WHERE " + MarketId3 + " = ?"
The in a method I prepare a list of PreparedStament to execute
final PreparedStatement statement1 = connection.prepareStatement(QUERY1);
final PreparedStatement statement2 = connection.prepareStatement(QUERY2);
final PreparedStatement statement3 = connection.prepareStatement(QUERY3);
for (ListOrder listOrder: listOrders)
{
statement1.setString(1, listOrder.Name);
statement1.setLong(2, listOrder.listId);
statement1.addBatch();
statement2.setString(1, listOrder.Name);
statement2.setLong(2, listName.listId);
statement2.addBatch();
statement3.setString(1, listName.Name);
statement3.setLong(2, listOrder.listId);
statement3.addBatch();
}
return new ArrayList<PreparedStatement>(){{add(statement1); add(statement2); add(statement3);}};
I'm a SQL noob. Is there any better way of doing it? I assume that MarketId 1 2 3 could be the same. ListNames could be null (there will be at least one)
UPDATE:
In code I would write something like this (prob change to HashMap)
for (ListOrder listOrder: listOrders)
{
for(Order order : orders)
{
if(order.marketID1 == listOrder.listID)
order.listName1 = listOrder.Name; //break if no dups
if(order.marketID2 == listOrder.listID)
order.listName2 = listOrder.Name;
if(order.marketID3 == listOrder.listID)
order.listName3 = listOrder.Name;
}
}
You can use update comma separated
UPDATE <TABLE>
SET COL1 = <VAL1>,
COL2= <VAL2>
WHERE <CONDITION>
Is it this what you expect as one update query?
Unless you are trying to update the same record, then there is no way to do this easily or efficiently in a single query. Otherwise, assuming this is the desired result, you could use an OR (or an AND if that is desired) statement such as:
UPDATE Order
SET ListName1=?, ListName2=?, ListName3=?
WHERE MarketId1=? OR MarketId2=? OR MarketId3=?
You might also consider updating your table to use a one:many relationship which might make your queries easier. For example:
Order
--------
id (key)
name
etc
Market_List
--------
id (key)
order_id (fk)
market
listname

Categories