Case insensitive query with cyrillic data - android

I'm developing and app, which has to store elements from an ftp server to a local sqlite database on an Android device and display the elements after a search. It's been done and it's working.
Now i want to add a search method that is not case sensitive. For instance if there are apples with names such as Red apple, yellow Apple, GreeN APPle... etc. they should all be displayed when searching with keyword apple or Apple or APPle. So far i've tried to make the search argument to lower or upper case, but it doesn't work when you throw in a random generated string. Is there a way to bring this functionallity wihtout proccessing outside of the database and if so, how?
This is the source for creating the table:
private static final String DATABASE_CREATE_ITEMTABLE =
"create table ItemTable(itemId text primary key, itemName text, itemGroup text);";
This is the source for the query:
private Cursor execQueryLike(String name) {
name = "%" + name + "%";
return database.query(DB_TABLE_ITEM, columnsitemTable, column
+ " LIKE ? ", new String[] { name }, null, null, KEY_COLUMN_ITEM_NAME, null);

Related

<column definition name> or <table constraint> expected, got 'Index'

I have got the error message " or expected, got 'Index'" when I was trying to create a table and I do not really understand why is the code expecting a column definition or table constraint at this line
I have tried with changing the whitespaces, however that only change the place where the error is prompted. The content of the error message does not change
This is the part that I have declared the strings
public class TaskEntry implements BaseColumns {
public static final String TABLE = "Users";
public static final String INDEX = "Index";
public static final String COL_TASK_TITLE = "title";
}
The following is my code for the creating table part
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + Item_contract.TaskEntry.TABLE + " ( " +
Item_contract.TaskEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
Item_contract.TaskEntry.INDEX + " INTEGER NOT NULL, " +
Item_contract.TaskEntry.COL_TASK_TITLE + " TEXT NOT NULL" + ");";
db.execSQL(createTable);
}
You cannot use INDEX as a column name as it is a keyword.
The SQL standard specifies a large number of keywords which may not be
used as the names of tables, indices, columns, databases, user-defined
functions, collations, virtual table modules, or any other named
object. The list of keywords is so long that few people can remember
them all. For most SQL code, your safest bet is to never use any
English language word as the name of a user-defined object.
SQL As Understood By SQLite - SQLite Keywords
So change
public static final String INDEX = "Index";
perhaps to
public static final String INDEX = "IX";
You could enclose the column name if you really wanted it to be INDEX e.g.
public static final String INDEX = "[Index]";
As per :-
If you want to use a keyword as a name, you need to quote it. There are four ways of quoting keywords in SQLite:
'keyword' A keyword in single quotes is a string literal.
"keyword" A keyword in double-quotes is an identifier.
[keyword] A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.
`keyword` A keyword enclosed in grave accents (ASCII code 96) is an identifier. This is not standard SQL. This quoting mechanism is used by MySQL and is included in SQLite for compatibility.
SQL As Understood By SQLite - SQLite Keywords
Note
You will have to do one of the following to get the onCreate method to run and thus alter the schema:-
Delete the App's data.
Uninstall the App.

FTS4 sqlite MATCH not working

I've tried several methods from here:
SQLite FTS example doesn't work
and here:
Full text search example in Android (best tutorial so far i think)
However, my search returns 0 results!
Here is what I've tried:
String key = "a";
Cursor c = db.query(true, "texts_virtual",
new String[]{"id","title_normalized"},
"title_normalized MATCH '"+key+"'",
null, null, null, null, null);
= 0 Results;
String query = "a";
String[] params = {"%" +query+ "%"};
Cursor c = db.rawQuery("SELECT * FROM texts_virtual WHERE title_normalized MATCH ?", params);
= 0 Results too
I know that the virtual table is correctly working because I can do this:
String queryText = "a"; //here i test other texts and they worked too
String query = "select * from texts_virtual where title_normalized like ? order by number";
String[] params = {"%" + queryText + "%"};
Cursor c = db.rawQuery(query, params);
so this prove that the texts_virtual is working, what is not working are the queries, but I don't know why, not error, nothing, just 0 results.
Also after I make it work, I'm planning to use multiple terms search in 2 columns
user type "WordA WordB WordC"
it search for each word in the 2columns and return the results, but this if for a future task....
Edit
Table Code Creation:
CREATE TABLE texts (id INTEGER PRIMARY KEY AUTOINCREMENT, title_normalized....);
INSERT INTO texts (id, titulo_normalized...) VALUES (1, 'aaaaaa', ...);
and go on for more inserts, and at the end the virtual creation
CREATE VIRTUAL TABLE texts_virtual USING fts4(content="texts", id, title_normalized, ..other fields);
i can query texts_virtual using LIKE but not MATCH, match return 0 results =/
Edit 2 how the table looks:
Table: texts_virtual
----------------------------
id --- title_normalized
--------------------------
1 --- aaaaaaaaab
2 --- abbbbbbbbb
3 --- bbbbbabbbb
4 --- bbbbbbbbbb
The FTS module searches for words (where the exact definition depends on the tokenizer used), or at best for words with a prefix.
MATCH words as designed; it does not find "a" because there is no word "a" in your data.
If you want to find substrings inside words, you must use LIKE.
You are using % as a joker. In FTS requests, You have to use * instead.
LIKE "%word%"
MATCH "*word*"
I've noticed that for very short words (less than 3 letters), LIKE is faster than MATCH. For longer words, MATCH is faster.

Check if Query in sqlite is empty in a bindView method

How to check if data queried from android sqlite database is empty in a bindView method?
This is what I have done so far, but I think I am doing the wrong thing.
UPDATE
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
SQLiteDatabase db;
db = openOrCreateDatabase(
"no.db"
, SQLiteDatabase.CREATE_IF_NECESSARY
, null
);
//CREATE TABLES AND INSERT MESSAGES INTO THE TABLES
String CREATE_TABLE_NOTICES = "CREATE TABLE IF NOT EXISTS notices ("
+ "ID INTEGER primary key AUTOINCREMENT,"
+ "NOT TEXT,"
+ "DA TEXT)";
db.execSQL(CREATE_TABLE_NOTICES);
Cursor myCur = null;
// SQLiteDatabase db;
myCur = db.rawQuery("SELECT ID as _id,NOT,DA FROM notices order by ID desc", null);
mListAdapter = new MyAdapter(Page.this, myCur);
setListAdapter(mListAdapter);
}
#Override
public void bindView(View view, Context context, Cursor myCur) {
TextView firstLine=(TextView)view.findViewById(R.id.firstLine);
if(myCur==null){
String message="No Message";
firstLine.setText(message);
}
}
The keyword NOT is a reserved word in MySQL. I'd be very surprised if it's not a reserved word in SQLite.
I think the problem is here:
SELECT ID as _id,NOT,DA FROM notices order by ID desc
-- ^^^
It looks like the reserved word NOT is being used as a column name. To use that as an identifier, it will need to be "escaped", by enclosing it in backtick characters.
SELECT ID as _id,`NOT`,DA FROM notices ORDER BY ID DESC
-- ^ ^
That's the normative pattern in MySQL. For SQLite, you use the (MySQL compatible ) backtick characters, or you can use double quotes (more ANSI standard compliant.)
It's also possible to qualify the column name. (I'm certain this works in MySQL).
SELECT n.ID AS `_id`, n.NOT, n.DA FROM notices n ORDER BY n.id DESC
-- ^^ ^^ ^^ ^ ^^
References:
MySQL Reference Manual: 9.3 Keywords and Reserved Words https://dev.mysql.com/doc/refman/5.5/en/keywords.html
Certain keywords, such as SELECT, DELETE, or BIGINT, are reserved and require special treatment for use as identifiers such as table and column names.
SQLite: SQLite Keywords https://www.sqlite.org/lang_keywords.html
If you want to use a keyword as a name, you need to quote it. There are four ways of quoting keywords in SQLite:
It may also be a problem in the CREATE TABLE statement. Since you are creating the table, you have the option of using a different name for the column, a name which is not a reserved word.

Android / SQLite - backticks, single quotes or double quotes?

Suppose I had a method like this...
long getNumItemsFromDb() {
SQLiteDatabase db = dbhelper.getReadableDatabase();
try {
String query = "SELECT " + COL_NAME +
" FROM " + TABLE_NAME +
" WHERE " + COL_NAME + " = ?";
String[] args = new String[] {"whatever"};
return DatabaseUtils.longForQuery(db, query, args);
} finally {
db.close();
}
}
...but it's possible that, for example, String COL_NAME = "select"; and String TABLE_NAME = "from"; - which is going to break the query. So, I'd obviously need to surround those values in my query String with either backticks, single quotes or double quotes - but which of these is the best practice for Android / SQLite?
NB - I have simplified my query String above to make this question simpler and more to the point. So, in reality, I do need to create the SQL manually like this rather than using one of the helper methods in Android.
NB2 - I have seen similar questions here and here but the questions/answers do not address SQLite and Android.
I'd say go with the standard.
The ANSI standard is double quotes for quoting fields/identifiers, and that works well on SQLite.
Note that some other RDBMS's may need some help to follow the standard, but following it will allow your SQL to run unchanged on as many RDBMS's/platforms as possible.
If you were to use androids class SQLitedatabase you could just simply use the query method and not worry if your selection string contains any of the identifiers.
Though when using FTS tables with MATCH identifier I noticed that you must surround the searchable string with percent signs like this: "%"+str+"%", otherwise it only matches up until a space.

Android SqLite no such column _id exception

Don't immediately flag me for a duplicate question. My issue is different because I have a correctly formatted SQL query.
public static final String TABLE_NAME = "log";
public static final String COLUMN_ID = "_id";
public static final String LOG_TEXT = "logtext";
private static final String TABLE_CREATE = "CREATE TABLE " + TABLE_NAME + " (" +
COLUMN_ID + " integer primary key autoincrement, " +
LOG_TEXT + " TEXT not null);";
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(TABLE_CREATE);
}
and I query here
String[] columns = {LOG_TEXT,COLUMN_ID};
Cursor cursor = helper.getReadableDatabase().query(TABLE_NAME, columns, null, null, null, null, COLUMN_ID + " desc");
and I catch this the exception generated containing the sql query.
catch(Exception e){
Log.D("sql Exception",e.getMessage());}
and it returns
no such column: _id: , while compiling: SELECT logtext, _id FROM log ORDER BY _id desc
I'm familar with Oracle SQL and relational databases in general. Is it my ORDER BY clause? I was certain you can ALWAYS use order by. It doesn't have the same behavior as GROUP BY.
Any ideas on why the exception?
Incase anyone wants to see i'm updating with my ArrayAdaptor statements. I'm using the cursor in a listview
String[] data = query();
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, data);
listView.setAdapter(adapter);}
Rewrite
Whenever you change the schema in TABLE_CREATE you must inform you app of these changes, they will not happen automatically when you change TABLE_CREATE. The easiest way to do this is to increment your database_version in your extended SQLiteOpenHelper class. You discovered you can also uninstall / reinstall the app, for the same results. If you are savvy with SQL you could ALTER the table. But whatever the method you must make sure that you app makes the schema changes before trying to access the new columns...
Also for SQLite:
_id integer primary key
is synonymous with:
_id integer primary key autoincrement not null
And queries use descending as the default order, so ORDER BY _id is the same as ORDER BY _id DESC.
Had the same problem, meaning it should have worked but didn't (had some typos in the create command that I fixed but that still didn't help). A colleague then told me to try clearing the data (just at AppInfo and then "Clear Data") which solved my problem, apparently the old database (that didn't work) was still there and had to be cleared out first.
I just put this answer here in case anybody else like me (android beginner) stumbles across this problem, because I went through dozens of stackoverflow threads with this problem but not one offered this possibility/solution and it bothered me for quite some time.
Did you add the definition of the _id column to your create statement later on, i.e. after the code had already been run once? Databases are persisted files, so if you modify the table structure in your code you need to make sure you clear your application's data so the database file can ge re-created with the correct table/column data.

Categories

Resources