I am building a cursor for a select query. The WHERE section lookup value refers to a variable which is a path so it has several full stops in it.
The query doesnt like this and errors , the error says a col doesn't exist named with a name which is the lookup value i.e the path with stops in it. If I use the sqlEscape util on the variable it doesnt cause an error but the lookup fails.
Any suggestions please?
Without a bit of your code it is hard to say but I'm guessing you are putting your where clause together like this:
String value = "some.thing.or.other";
String where = "FIELD = " + value;
Try building a parameterized where clause instead
String value = "some.thing.or.other";
String where = "FIELD = ?";
SQLiteDatabase db = fDbOpener.getReadableDatabase();
Cursor results = db.query(TABLE_NAME, COLUMNS_LIST, where, new String[] { value }, null, null, null);
When you run the query method now, SQLite will substitute your value into the where clause specifically as a value - it won't try to interpret the value in any way so it can't mistake the full stops for syntax.
Related
I'm trying to select some data from database and I have two slices of code to do it:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = ?", new String[]{getSID(db)}, null, null, null);
and
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = " + getSID(db), null, null, null, null);
The difference between them is that first one seems to be more correct according to documentation, but it also doesn't work - cursor is empty. Instead of the second one - I'm getting all data I need.
So I tried to execute different SQL queries on my PC with a copy of database and that's what I've got:
SELECT col1, col2, col3 FROM SomeTables WHERE (id = '42')
This one doesn't work (and this query obviously equals to query, generated by first code sample)
SELECT col1, col2, col3 FROM SomeTables WHERE (id = 42)
And this one works fine (equals to query from second code sample).
As I know, SQLite should perform type cast automatically, but something went wrong and I don't know why. Do you have any ideas about how first code sample can be fixed? (Or, perhaps, database?)
If it matters, here's simplified CREATE script of the table with id field:
CREATE TABLE SomeTable ( ID PRIMARY KEY, col1, col2, [...] )
UPD: And, by the way, getSID(db) returns String Object.
That query parameters can only be strings is a horrible design error in the Android database API.
Despite what the documentation says, you should use parameters only for actual string values; integer values can be safely embedded directly into the SQL string. (For blobs, you must use a function that accepts ContentValues.)
Please note that while SQLite uses dynamic typing, values of different types do not compare equal in most cases (SELECT 42='42'; returns 0).
There are some cases where SQLite does automatically convert values due to type affinity (in your case, this would happen if you declared the id column as INTEGER), but this is rather counterintuitive, so it should not be relied upon.
According to SQLite documentation,
Any column in an SQLite version 3 database, except an INTEGER PRIMARY KEY column, may be used to store a value of any storage class.
In context of my case, that means that we can't be sure what data type will be stored in columns. If you can control and convert data types when they're putting into database - you can convert id values to TEXT when adding data to database and use selectionArgs easily. But it's not an answer for my question, because I have to deal with database content as is.
So, possible solutions:
a) embed integer values in selection string without wrapping them into ':
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"id = " + getSID(db), null, null, null, null);
b) cast values from selectionArgs: CAST(? as INTEGER) or CAST(id AS TEXT). I think, converting column to TEXT is better solution, because right operand is always TEXT, but the left one can be anything. So:
cursor = builder.query(db,
new String[]{"col1", "col2", "col3"},
"CAST(id AS TEXT) = ?",
new String[]{getSID(db)}, null, null, null);
You need to convert your int id into string before passing to your query because the parameter array is of type string. For example:
cursor = builder.query(db, new String[]{"col1", "col2", "col3"},
"id = ?", new String[]{String.valueOf(getSID(db))}, null, null, null);
The reason why it works in second type of query is because you are appending the integer value with string which automatically converts the int into String. For example:
int i = 10;
String s = i + ""; //now 10 is in string
I have database with three columns.
I would like to query the database, based on one column which can have multiple values.
For single parameter we can the normal query method where cardName is String[]
Cursor cursor = database.query(Database.TABLE_COUPON_CARD, allColumns,Database.COLUMN_CARD_NAME + " = ?", cardName, null, null,null);
but if there are more than one value, I get a Android SQLite cannot bind argument exception
For multiple values of the same column we can use IN statement but, here how do I write the QUERY or how should i form the rawQuery
String whereClause = Database.COLUMN_CARD_NAME+ " IN(?)";
Cursor cursor = database.query(Database.TABLE_COUPON_CARD, allColumns,whereClause,new String[][]{cardName}, null, null,null);
Android QUERY doesnot take array of array.
What should the correct query be?
TEMPORARY SOLUTION
Currently I have created a method which dynamically creates the clause.
private static StringBuilder buildInClause(String[] myStringArray){
StringBuilder fullString=new StringBuilder();
fullString.append("(");
for(int i=0;i<myStringArray.length;i++){
fullString.append(" '"+myStringArray[i]+"' ");
if(i!=myStringArray.length-1){
fullString.append(",");
}
}
fullString.append(")");
return fullString;
}
If anyone has any other solution please do share.
For two values: IN(?,?). For three values: IN(?,?,?). Get the idea? Each ? corresponds to a single literal in the selection args array.
I'm trying to get database row by it's ID, but somehow query doesn't return that row. The sql query SELECT * From Table1 Where _id = 100 works good, so I don't know what's the reason. Here is the code of the query:
String [] selectedArgs = new String [] {String.valueOf(selectedItemId)};
String selection = Tables.Table1.COLUMN_ID + "=?";
String [] columns = {Tables.Table1.COLUMN_ID, Tables.Table1.COLUMN_NAME};
Cursor c = foodDB.query(Tables.Food.TABLE_NAME, columns, selection, selectedArgs, null, null, null);
Does anybody have any suggestions?
The problem is that your ID field is a number, while the parameter is a string; the query function does not allow other parameter types for some strange reason.
Try using an expression like COLUMN_ID + " = CAST(? AS INTEGER)".
If your query had only one result column, you could use a separate SQLiteStatement object where you'd be able to use bindLong().
Just in case somebody need it, i have used rawQuery() method for such type of query to work, because query() doesn't work.
I'm writing a method to update default settings in a table. The table is very simple: two columns, the first containing labels to indicate the type of setting, the second to store the value of the setting.
At this point in the execution, the table is empty. I'm just setting up the initial value. So, I expect that this cursor will come back empty. But instead, I'm getting an error (shown below). The setting that I am working with is called "lastPlayer" and is supposed to get stored in the "SETTING_COLUMN" in the "SETTINGS_TABLE". Here's the code:
public static void updateSetting(String setting, String newVal) {
String table = "SETTINGS_TABLE";
String[] resultColumn = new String[] {VALUE_COLUMN};
String where = SETTING_COLUMN + "=" + setting;
System.err.println(where);
SQLiteDatabase db = godSimDBOpenHelper.getWritableDatabase();
Cursor cursor = db.query(table, resultColumn, where, null, null, null, null);
System.err.println("cursor returned"); //I never see this ouput
\\more
}
sqlite returned: error code = 1, msg = no such column: lastPlayer
Why is it saying that there is no such column lastPlayer? I thought that I was telling the query to look at the column "SETTING_COLUMN" and return the record where that column has a value "lastPlayer". I'm confused. Can somebody straighten me out? I've been looking a this for an hour and I just don't see what I am doing wrong.
Thanks!
You're not properly building/escaping your query. Since the value lastPlayer is not in quotes, your statement is checking for equality of two columns, which is what that error message is saying.
To properly build your query, it's best to not do this manually with String concatenation. Instead, the parameter selectionArgs of SQLiteDatabase.query() is meant to do this.
The parameters in your query should be defined as ? and then filled in based on the selectionArgs. From the docs:
You may include ?s in selection, which will be replaced by the values
from selectionArgs, in order that they appear in the selection. The
values will be bound as Strings.
So, your code would look like this:
String where = SETTING_COLUMN + " = ?";
Cursor cursor = db.query(table, resultColumn, where, new String[] { setting }, null, null, null);
I'm getting an annoying error when trying to query some data in SQLite.
Here is my code:
Cursor cursor= db.query(TABLE_IMAGES, new String[]{"_id"}, "name" +" = "+compareToThis, null, null, null, null);
I'm just returning the cursor as a string.
The error is saying:
no such column: compareToThis: while compiling.....the statement
My question is: why is SQLite setting the compareToThis attribute as a column when it's just a value?
How can I fix this?
Thanks in advance.
Cursor cursor= db.query(TABLE_IMAGES, new String[]{"_id"}, "name" +" = ?", new String[]{compareToThis}, null, null, null);
The selection must include placeholder for parameter, and the next argument should be the array of parameters.
The solution by Vladimir works, however if you are like me and wonder why your approach did not work initially when it should have, here is why:
It is because it expects an integer unless you used (single or double) quotation marks to indicate that it is a string.
For example, in MySql this would return no results:
SELECT * FROM clients WHERE firstName = Bob; -- This will not work.
However when you surround it with quotations, it will return a result because it identifies Bob as a String literal.
Select * FROM clients WHERE firstName = 'Bob'; -- Single quotes work.
Select * FROM clients WHERE firstName = "Bob"; -- Double quotes as well.
Therefore for it to work, you would have to surround your compareToString with single quotes, as Muhhammad mentioned within the comments.
Cursor cursor= db.query(TABLE_IMAGES, new String[]{"_id"}, "name" +'" = "+compareToThis+"'", null, null, null, null);