SQLite database "No such column" error on verified existing column [duplicate] - java

This question already has an answer here:
android.database.sqlite.SQLiteException: no such column or name
(1 answer)
Closed 3 months ago.
I am stuck on an "SQLiteException: no such column:" error. I am trying to make some code to check if an item exists in the database before storing it, I don't know if it's the best way or not but it does the job. Or not really, when I use all numbers for the data in the particular column that I'm searching it works fine. But if there is any letter in the column data it crashes.
The MainActivity
private ConversationsDatabaseHelper db;
//onCreate stuff here
db = new ConversationsDatabaseHelper(this);
String threadId = "886";
Log.d(TAG, "dbTest: EXISTS; " + db.conversationExists(threadId));
and in the databaseHelper class is the converstionExists function
public boolean conversationExists(String threadId) {
// Select All Query
String selectQuery = "SELECT * FROM " + Conversations.TABLE_NAME + " WHERE " +
Conversations.COLUMN_THREAD_ID + " LIKE " + threadId;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
boolean returnValue = false;
// Check if this message exists
if (cursor.moveToFirst()) {
returnValue = true;
}
// close db connection
db.close();
return returnValue;
}
So if I use for example "886" as the threadId value then all is fine. If I create a row with matching threadId then it returns true. In this case I did not so hence false.
stack trace...
dbTest: EXISTS; false
but using a886 results in
Caused by: android.database.sqlite.SQLiteException: no such column: a886 (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM conversations WHERE thread_id LIKE a886
and 88a6 results in this
Caused by: android.database.sqlite.SQLiteException: unrecognized token: "88a6" (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM conversations WHERE thread_id LIKE 88a6
It almost looks like mixing letters and numbers might be part of the reason here but should not be as the column was created to hold TEXT datatype. here is the database create table query string.
public static final String TABLE_NAME = "conversations";
public static final String COLUMN_ID = "id";
public static final String COLUMN__ID = "_id";
public static final String COLUMN_GROUP_ID = "group_id";
public static final String COLUMN_LAST_MESSAGE_ID = "last_message_id";
public static final String COLUMN_THREAD_ID = "thread_id";
public static final String COLUMN_ADDRESS = "address";
public static final String COLUMN_CONTACT = "contact";
public static final String COLUMN_BODY = "body";
public static final String COLUMN_DATE = "date";
public static final String COLUMN_TYPE = "type";
public static final String COLUMN_STATE = "state";
public static final String COLUMN_READ = "read";
public static final String COLUMN_STATUS = "status";
public static final String COLUMN_CT = "ct";
// Create table SQL query
public static final String CREATE_TABLE =
"CREATE TABLE " + TABLE_NAME + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY ,"
+ COLUMN_LAST_MESSAGE_ID + " TEXT,"
+ COLUMN__ID + " TEXT,"
+ COLUMN_GROUP_ID + " TEXT,"
+ COLUMN_THREAD_ID + " TEXT,"
+ COLUMN_ADDRESS + " TEXT,"
+ COLUMN_CONTACT + " TEXT,"
+ COLUMN_BODY + " TEXT,"
+ COLUMN_DATE + " TEXT,"
+ COLUMN_TYPE + " TEXT,"
+ COLUMN_STATE + " TEXT,"
+ COLUMN_READ + " TEXT,"
+ COLUMN_STATUS + " TEXT,"
+ COLUMN_CT + " TEXT"
+ ")";
I am "up a creek" with this and any help would be greatly appreciated.

The value a886 should be a text/string literal not a numeric literal. Therefore it should be enclosed in single quotes. The errors are because:-
a886 fails with no column found as it's taken to be a column name as it's not a literal.
whilst 88a6 is first not a valid literal (due to the a) and therefore a column name but then an invalid column (cannot start with a numeric unless enclosed) name and thus not a known token.
See Literal Values (Constants)
You could fix this using (enclosing the threadId in single quotes ) :-
String selectQuery = "SELECT * FROM " + Conversations.TABLE_NAME + " WHERE " +
Conversations.COLUMN_THREAD_ID + " LIKE '" + threadId + "'";
However, it is recommended to use bound parameters to protect against SQL Injection.
Thus it would be recommended to use :-
String selectQuery = "SELECT * FROM " + Conversations.TABLE_NAME + " WHERE " +
Conversations.COLUMN_THREAD_ID + " LIKE ?";
along with :-
Cursor cursor = db.rawQuery(selectQuery, new String[]{threadId});
i.e. the ? is replaced by the threadId value properly enclosed.
You may wish to consider using the convenience query method rather than rawQuery, this would be :-
Cursor cursor = db.query(Conversations.TABLE_NAME,null,Conversations.COLUMN_THREAD_ID + " LIKE ?", new String[]{theadId},null,null, null);
The SQL is built for you.
It almost looks like mixing letters and numbers might be part of the reason here but should not be as the column was created to hold TEXT datatype.
SQlite has no issue storing any value in any type. The type, which itself can be virtually anything (rules are used to determine the resultant type), is only an indication of the value that will be stored. The only exception is that a rowid or an alias of the rowid MUST be an integer value (your id column is an alias of the rowid column).

Related

SQLite is not creating any table in Android studio

hi i am trying to make a raffle table but however i did created the database but no table is create, the run panel shows that i created it but the sqlite browser shows that there is nothing in it.
here is the code:
in the database java:
public void onCreate(SQLiteDatabase db)
{
// Note the use of super, which calls the constructor of the SQLiteOpenHelper class,
// which does the actual work of opening the database.
Log.d(TAG, "DatabaseHelper onCreate");
Log.d(TAG, RaffleTable.CREATE_STATEMENT);
db.execSQL(RaffleTable.CREATE_STATEMENT);
}
in the raffletalbe.java:
public class RaffleTable {
public static final String TABLE_NAME = "Raffle";
public static final String KEY_ID = "raffle_id";
public static final String KEY_NAME = "raffle_name";
public static final String KEY_PRICE = "price";
public static final String KEY_START = "raffle_start";
public static final String KEY_END = "raffle_end";
public static final String KEY_DESCRIPTION = "raffle_description";
public static final String KEY_TYPE = "raffle_type";
public static final String KEY_PRIZE = "raffle_prize";
public static final String KEY_LIMIT = "raffle_limit";
public static final String CREATE_STATEMENT = "CREATE TABLE "
+ TABLE_NAME
+ " (" + KEY_ID + " integer primary key autoincrement, "
+ KEY_NAME + " string not null, "
+ KEY_DESCRIPTION + " string, "
+ KEY_START + " string not null, "
+ KEY_END + " string not null, "
+ KEY_TYPE + " integer not null, "
+ KEY_LIMIT + " integer, "
+ KEY_PRIZE + " String, "
+ KEY_PRICE + " real);";
what it shows in the run panel:
D/RaffleDatabase: DatabaseHelper onCreate
CREATE TABLE Raffle (raffle_id integer primary key autoincrement, raffle_name string not null, raffle_description string, raffle_start string not null, raffle_end string not null, raffle_type integer not null, raffle_limit integer, raffle_prize String, price real);
here is the code i used to insert the table:
Raffle Ruffle1 = new Raffle();
Ruffle1.setRuffleDes("742 Evergreen Terrace");
Ruffle1.setRuffleEnd("20190102");
Ruffle1.setRuffleStart("20190101");
Ruffle1.setRuffleLimit(5);
Ruffle1.setRuffleName("testing");
Ruffle1.setRufflePrize("cooper");
Ruffle1.setRuffleType("Normal");
Ruffle1.setRufflePrice(1000);
Raffle Ruffle2 = new Raffle();
Ruffle2.setRuffleDes("742 Evergreen Terrace");
Ruffle2.setRuffleEnd("20190102");
Ruffle2.setRuffleStart("20190101");
Ruffle2.setRuffleLimit(5);
Ruffle2.setRuffleName("testing");
Ruffle2.setRufflePrize("cooper");
Ruffle2.setRuffleType("Normal");
Ruffle2.setRufflePrice(1000);
RaffleTable.insert(db, Ruffle1);
RaffleTable.insert(db, Ruffle2);
There is nothing wrong with your code. You just need to put the updated file in your browser. May be your browser is reading the old file that's why you're not able to read the updated content.

How to use format string with SQL query by resources

I have some string const inside code. Can I put all this into resources strings.xml? I assume that the possibility of separate use of column names will remain. It is necessary to search for the index of posts in future requests to the database. Not to use the indexes the numbers is confusing, uncomfortable.
private static final String NAME_DB = "cars.db";
private static final String TABLE_NAME = "cars";
private static final String COL_BRAND = "brand";
private static final String COL_MODEL = "model";
private static final String COL_COLOR = "color";
private static final String COL_MAX_SPEED = "max_speed";
private static final String COL_ENGINE_POWER = "engine_power";
private static final String CREATE_TABLE =
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
COL_BRAND + " TEXT NOT NULL, " +
COL_MODEL + " TEXT NOT NULL, " +
COL_COLOR + " TEXT, " +
COL_MAX_SPEED + " INTEGER," +
COL_ENGINE_POWER + " INTEGER)";
private static final String INSERT_DEFAULT_VALUES =
"INSERT INTO " + TABLE_NAME + "(brand, model, color, max_speed, engine_power) VALUES" +
"('Audi', 'Q7 II', 'White', 233, 252)," +
"('Acura', 'ZDX', 'Black', 241, 300)," +
"('BMW', 'X1 I', 'Blue', 205, 204)," +
"('Hyundai', 'Solaris', 'Red', 100, 100)," +
"('Hyundai', 'Tucson', 'Gray', 150, 177)," +
"('BMW', '8 G14', 'Black', 250, 320)";
private static final String SELECT_ALL = "SELECT * FROM " + TABLE_NAME;
private static final String SELECT_TOP_1 = "SELECT * FROM " + TABLE_NAME + " LIMIT 1";
Example code
DatabaseAdapter(Context context) {
db = context.openOrCreateDatabase(NAME_DB, MODE_PRIVATE, null);
db.execSQL(CREATE_TABLE);
Cursor cursor = db.rawQuery(SELECT_TOP_1, null);
if (!cursor.moveToFirst()) {
db.execSQL(INSERT_DEFAULT_VALUES);
}
}
String[] selectAll() {
Cursor cursor = db.rawQuery(SELECT_ALL, null);
if (!cursor.moveToFirst()) {
return null;
}
ArrayList<String> list = new ArrayList<>();
while (cursor.moveToNext()) {
list.add(
cursor.getString(cursor.getColumnIndex(COL_BRAND)) + " " +
cursor.getString(cursor.getColumnIndex(COL_MODEL)) + " " +
cursor.getString(cursor.getColumnIndex(COL_COLOR)) + " " +
cursor.getString(cursor.getColumnIndex(COL_MAX_SPEED)) + " " +
cursor.getString(cursor.getColumnIndex(COL_ENGINE_POWER))
);
}
return list.toArray(new String[0]);
}
There are some solutions with SQL in XML. Look if you can use one of those.
However IMHO it is better to centralize the code and keep text there, without constants even.
Separate concerns: database query and resulting object. This can be done by providing a Stream of a low-level result set object, that using classes can map to their own classes.
Decouples classes; keeps the layers separate. (Maybe less interesting on Android.)
The using code becomes nicely compact, the queries being elsewhere.
My arguments:
Less back and forth jumping to different sources
Better readability
Column names do not change
Capitals of constants are less readable
Keeping the code together prevents similar queries to be spread around unattended
However it still is better than SQL in the higher level business code, to isolate SQL in XML to have smaller source, queries elsewhere. So at least do that.
Java - Storing SQL statements in an external file

Android Sqlite Column Exists but returned -1

I have an android app where I've Created a Database Table named chats with the following Schema
package com.messaging.chatify.Schema;
public class Messages {
public static final String TABLE_MESSAGES = "chats";
public static final String MESSAGE_ID = "_id";
public static final String MESSAGE_TEXT = "text";
public static final String MESSAGE_ATTACHMENT = "attachement";
public static final String MESSAGE_SENDER = "msgfrom";
public static final String MESSAGE_RECEIVER = "msgto";
public static final String MESSAGE_ISREAD = "isRead";
public static final String MESSAGE_TIME = "mtime";
public static final String[] ALL_COLUMNS = { MESSAGE_ID, MESSAGE_TEXT, MESSAGE_ATTACHMENT, MESSAGE_SENDER, MESSAGE_RECEIVER, MESSAGE_ISREAD };
public static final String CREATE_STATEMENT =
"CREATE TABLE IF NOT EXISTS " + TABLE_MESSAGES + "(" +
MESSAGE_ID + " TEXT PRIMARY KEY, " +
MESSAGE_TIME + " TEXT, " +
MESSAGE_TEXT + " TEXT, " +
MESSAGE_ATTACHMENT + " TEXT, " +
MESSAGE_SENDER + " TEXT, " +
MESSAGE_RECEIVER + " TEXT, " +
MESSAGE_ISREAD + " INTEGER" + ");";
public static final String DROP_STATEMENT =
"DROP TABLE IF EXISTS " + TABLE_MESSAGES;
}
but unfortunately when I try to get the column mtime from this table,
I get -1
I've exported the database to my computer and checked it with sqlite browser, the column is created and exists
here are the screen shots of the sqlite browser schema and records
SQLITE BROWSER SCHEMA OUTPUT
SQLITE BROWSER DATA OUTPUT
any suggestion how to get rid of this issue?
I suspect you may have omitted the column in :-
public static final String[] ALL_COLUMNS = { MESSAGE_ID, MESSAGE_TEXT, MESSAGE_ATTACHMENT, MESSAGE_SENDER, MESSAGE_RECEIVER, MESSAGE_ISREAD };
Perhaps changing it to be (i.e. adding MESSAGE_TIME):-
public static final String[] ALL_COLUMNS = { MESSAGE_ID, MESSAGE_TEXT, MESSAGE_ATTACHMENT, MESSAGE_SENDER, MESSAGE_RECEIVER, MESSAGE_ISREAD, MESSAGE_TIME };
will resolve the issue. If not then you need to edit your question to include the query that is resulting in the -1.
Alternatively, you could use :-
public static final String[] ALL_COLUMNS = {"*"};
P.S. for all columns you can use * (e.g. SELECT * FROM mytable) (as used in the alternative solution above) or if using the query method you can use null for all columns as the 2nd paremeter.

Autoincrement not working on ID

I'm having some trouble getting my autoincrement to work in SQL in my android app.
public static final String TABLE_NAME = "collections";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_TITLE = "title";
public static final String CREATE_STATEMENT = "CREATE TABLE " + TABLE_NAME +
"(" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
COLUMN_TITLE + " TEXT NOT NULL" + ")";
Are there any major problems with the create statement that could cause this?
There is no need to add AUTOINCREMENT NOT NULL to the primary key, As primary key(column) is supposed to be auto-increment and it can't be null.
following is an example of a SQL query which you may edit to create your own table.
public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + "Your_Table_Name" +
" (" + BaseColumns._ID + " INTEGER PRIMARY KEY," +
"first_column_name" + " TEXT" + "," +
"second_column_name" + " TEXT" + ")";
and BaseColumns is in interface provided by android in package android.provider which you may use to create a primary column with name "_id"
When you insert a new value do not define id (it will be automatically generated) just use COLUMN_TITLE.
Even in scheme you can skip id definition, because sqlite use RAWID internally and latter aliases your ID to RAWID.

Android unable to write datetime to sqllite database

I'm using the Google Tasks API in my app. One of the fields in my app "due date" requires a DateTime object. Im using the Android datepicker dailog and an EditText view to capture the due date and then converting the user input into the datetime format. When I try to write to my SQLite database I get the following exception.
Error inserting due=2015-06-14T15:58:38.572-04:00 title=Test app _id=TaskId0.07429873487580996 status=needsAction notes=Test write
android.database.sqlite.SQLiteException: table tasks has no column named due (code 1): , while compiling: INSERT INTO tasks(due,title,_id,status,notes) VALUES (?,?,?,?,?)
which is confusing because I do define a column named "due". Further up in the logs there is another exception.
06-14 15:58:38.607 15395-15395/com.github.idclark.forgetmenot E/EDITFRAGMENT﹕ null
java.text.ParseException: Unparseable date: "06/14/15" (at offset 8)
at java.text.DateFormat.parse(DateFormat.java:579)
at com.github.idclark.forgetmenot.EditFragment.getTaskDueDate(EditFragment.java:64)
The Schema is defined as
public static final class TaskEntry implements BaseColumns {
public static final String TABLE_NAME = "tasks";
public static final String COLUMN_TASK_ID = "_id";
public static final String COLUMN_TASK_TITLE = "title";
public static final String COLUMN_TASK_UPDATED = "updated";
public static final String COLUMN_TASK_SELFLINK = "selfLink";
public static final String COLUMN_TASK_PARENT = "parent";
public static final String COLUMN_TASK_POSITION = "position";
public static final String COLUMN_TASK_NOTES = "notes";
public static final String COLUMN_TASK_STATUS = "status";
public static final String COLUMN_TASK_DUE = "due";
public static final String COLUMN_TASK_COMPLETED = "completed";
public static final String COLUMN_TASK_DELETED = "deleted";
public static final String COLUMN_TASK_HIDDEN = "hidden";
so the "due" column does exist. And the table is created by
#Override
public void onCreate(SQLiteDatabase db) {
//status must be either needsAction or completed
final String CREATE_TASK_TABLE =
"CREATE TABLE " + TaskEntry.TABLE_NAME + " (" +
TaskEntry._ID + " INTEGER PRIMARY KEY," +
TaskEntry.COLUMN_TASK_ID + "TEXT NOT NULL, " +
TaskEntry.COLUMN_TASK_TITLE + "TEXT NOT NULL, " +
TaskEntry.COLUMN_TASK_COMPLETED + "TEXT, " +
TaskEntry.COLUMN_TASK_NOTES + "TEXT, " +
TaskEntry.COLUMN_TASK_STATUS + "TEXT NOT NULL, " +
TaskEntry.COLUMN_TASK_DUE + "DATETIME, " +
TaskEntry.COLUMN_TASK_UPDATED + "DATETIME, " +
TaskEntry.COLUMN_TASK_PARENT + "TEXT, " +
TaskEntry.COLUMN_TASK_DELETED + "BOOLEAN, " +
TaskEntry.COLUMN_TASK_SELFLINK + "TEXT, " +
TaskEntry.COLUMN_TASK_POSITION + "TEXT, " +
TaskEntry.COLUMN_TASK_HIDDEN + "TEXT" + ")";
db.execSQL(CREATE_TASK_TABLE);
}
The due date conversion takes place in this method.
public DateTime getTaskDueDate() {
mDueDate = (EditText) getActivity().findViewById(R.id.task_due_date);
return new DateTime(mDueDate.getText().toString());
}
The data is then finally written to the database with
public boolean insertRow(Task task) {
ContentValues values = new ContentValues();
values.put(TaskContract.TaskEntry.COLUMN_TASK_STATUS, task.getStatus());
values.put(TaskContract.TaskEntry.COLUMN_TASK_ID,task.getId());
values.put(TaskContract.TaskEntry.COLUMN_TASK_TITLE,task.getTitle());
values.put(TaskContract.TaskEntry.COLUMN_TASK_DUE, task.getDue().toString());
values.put(TaskContract.TaskEntry.COLUMN_TASK_NOTES, task.getNotes());
SQLiteDatabase db = this.getWritableDatabase();
boolean createSuccessful = db.insert(TaskContract.TaskEntry.TABLE_NAME, null, values) > 0;
db.close();
return createSuccessful;
}
I'm confused as to why this write fails, and sql claims that there is no "due" column. Even though there is a parse exception, I see a timestamp in the logs as well. Is part of the problem that i'm calling .toString() on the datetime object before writing it to the db? I don't have a lot of sql experience and am genuinely confused as to what to make of these exceptions.
For the sqlite issue, you need to have whitespace between column names and types. For example, change
TaskEntry.COLUMN_TASK_DUE + "DATETIME, " +
to
TaskEntry.COLUMN_TASK_DUE + " DATETIME, " +
There's a similar problem with almost all of your columns.
After fixing the CREATE TABLE SQL, uninstall and reinstall your app to recreate the database.
For the date parsing problem, use a date format that matches your data. If you need detailed help with it, post a new question.

Categories